From d2a82db6a4cd9881c8a3d4f1d54d1166a3b90055 Mon Sep 17 00:00:00 2001 From: jade Date: Thu, 10 Sep 2026 13:28:40 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dat-was-sal/Dockerfile | 3 +- dat-was-sal/build.gradle | 4 +- .../cmm/converter/ClaimSearchConverter.java | 14 -- .../converter/MemoListRetrieverConverter.java | 17 -- .../mcc/biz/cmm/dto/ClaimSearchRequest.java | 16 -- .../mcc/biz/cmm/dto/ClaimSearchResponse.java | 22 -- .../biz/cmm/dto/MemoListRetrieverRequest.java | 16 -- .../cmm/dto/MemoListRetrieverResponse.java | 13 -- .../biz/cmm/usecase/ClaimSearchUseCase.java | 41 ---- .../cmm/usecase/MemoListRetrieverUseCase.java | 41 ---- .../usecase/impl/ClaimSearchUseCaseImpl.java | 69 ------ .../impl/MemoListRetrieverUseCaseImpl.java | 39 ---- .../dat/mcc/biz/lic/dto/LicToolRequest.java | 20 -- .../dat/mcc/biz/lic/dto/LicToolResponse.java | 15 -- .../lic/usecase/LicUnderwritingUseCase.java | 198 ------------------ .../impl/LicUnderwritingUseCaseImpl.java | 77 ------- .../dat/mcc/biz/sof/dto/SofToolRequest.java | 20 -- .../dat/mcc/biz/sof/dto/SofToolResponse.java | 15 -- .../sof/usecase/SofFieldActivityUseCase.java | 198 ------------------ .../impl/SofFieldActivityUseCaseImpl.java | 77 ------- .../dat/mcc/biz/sog/dto/SogToolRequest.java | 20 -- .../dat/mcc/biz/sog/dto/SogToolResponse.java | 15 -- .../usecase/SogSalesPerformanceUseCase.java | 198 ------------------ .../impl/SogSalesPerformanceUseCaseImpl.java | 77 ------- .../dat/mcc/biz/sot/dto/SotToolRequest.java | 20 -- .../dat/mcc/biz/sot/dto/SotToolResponse.java | 15 -- .../biz/sot/usecase/SotConsentUseCase.java | 198 ------------------ .../usecase/impl/SotConsentUseCaseImpl.java | 77 ------- .../dat/mcc/biz/spr/dto/SprToolRequest.java | 20 -- .../dat/mcc/biz/spr/dto/SprToolResponse.java | 15 -- .../spr/usecase/SprFieldInquiryUseCase.java | 198 ------------------ .../impl/SprFieldInquiryUseCaseImpl.java | 77 ------- .../mcc/infra/itrf/http/memo/MemoClient.java | 17 -- .../memo/io/MemoListRetrieverHttpRequest.java | 16 -- .../io/MemoListRetrieverHttpResponse.java | 13 -- .../infra/itrf/mci/ncla/MciNclaClient.java | 30 --- .../infra/itrf/mci/ncla/io/CLCNNB00001_I.java | 14 -- .../infra/itrf/mci/ncla/io/CLCNNB00001_O.java | 17 -- .../dat/mcc/sal/DatWasSalApplication.java | 20 +- .../src/main/resources/application-dev.yml | 8 +- .../src/main/resources/application-local.yml | 5 - .../src/main/resources/application-prod.yml | 9 +- .../src/main/resources/application-test.yml | 9 +- .../src/main/resources/application.yml | 5 +- .../src/main/resources/logback-spring.xml | 23 +- .../mock-responses/cmm_memo_retriever.json | 3 - .../lic_contract_review_document.json | 4 - .../lic_contract_review_history.json | 4 - .../lic_contract_review_result.json | 4 - .../lic_contract_review_status.json | 4 - .../mock-responses/lic_product_coverage.json | 4 - .../mock-responses/lic_product_info.json | 4 - .../lic_product_premium_table.json | 4 - .../lic_underwriting_additional_request.json | 4 - .../lic_underwriting_result.json | 4 - .../lic_underwriting_risk_grade.json | 4 - .../mock-responses/sms_cmm_claim_search.json | 5 - .../mock-responses/sof_activity_calendar.json | 4 - .../mock-responses/sof_activity_daily.json | 4 - .../sof_activity_report_status.json | 4 - .../mock-responses/sof_activity_summary.json | 4 - .../mock-responses/sof_call_activity.json | 4 - .../sof_customer_consulting.json | 4 - .../sof_field_support_request.json | 4 - .../mock-responses/sof_prospect_list.json | 4 - .../sof_training_completion.json | 4 - .../mock-responses/sof_visit_count.json | 4 - .../mock-responses/sog_incentive_summary.json | 4 - .../sog_monthly_performance.json | 4 - .../sog_new_contract_count.json | 4 - .../sog_performance_comparison.json | 4 - .../sog_premium_performance.json | 4 - .../sog_product_performance.json | 4 - .../mock-responses/sog_sales_ranking.json | 4 - .../mock-responses/sog_target_history.json | 4 - .../mock-responses/sog_target_progress.json | 4 - .../mock-responses/sog_target_summary.json | 4 - .../mock-responses/sot_consent_expiry.json | 4 - .../sot_consent_withdrawal.json | 4 - .../sot_customer_info_consent.json | 4 - .../sot_customer_info_consent_scope.json | 4 - .../sot_marketing_consent_channel.json | 4 - .../sot_marketing_consent_history.json | 4 - .../sot_marketing_consent_status.json | 4 - .../sot_subscription_design_consent.json | 4 - .../sot_subscription_design_detail.json | 4 - .../sot_tm_call_eligibility.json | 4 - .../spr_field_inquiry_answer.json | 4 - .../spr_field_inquiry_category.json | 4 - .../spr_field_inquiry_detail.json | 4 - .../spr_field_inquiry_escalation.json | 4 - .../mock-responses/spr_field_inquiry_faq.json | 4 - .../spr_field_inquiry_list.json | 4 - .../spr_field_inquiry_manager.json | 4 - .../spr_field_inquiry_satisfaction.json | 4 - .../mock-responses/spr_field_inquiry_sla.json | 4 - .../spr_field_inquiry_status.json | 4 - .../claim-search-resource-input-schema.json | 11 - .../claim-search-resource-output-schema.json | 16 -- .../main/resources/tool-service-manifest.yml | 32 +-- .../cmm/usecase/ClaimSearchUseCaseTest.java | 16 -- .../usecase/MemoListRetrieverUseCaseTest.java | 16 -- .../impl/ClaimSearchUseCaseImplTest.java | 47 ----- .../impl/LicUnderwritingUseCaseImplTest.java | 24 --- .../impl/SofFieldActivityUseCaseImplTest.java | 24 --- .../SogSalesPerformanceUseCaseImplTest.java | 24 --- .../impl/SotConsentUseCaseImplTest.java | 24 --- .../impl/SprFieldInquiryUseCaseImplTest.java | 24 --- 108 files changed, 41 insertions(+), 2456 deletions(-) delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/ClaimSearchConverter.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/MemoListRetrieverConverter.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/MemoListRetrieverUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/LicUnderwritingUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/SofFieldActivityUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/SogSalesPerformanceUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/SotConsentUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/SprFieldInquiryUseCase.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImpl.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/MemoClient.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpRequest.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpResponse.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/MciNclaClient.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_I.java delete mode 100644 dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_O.java delete mode 100644 dat-was-sal/src/main/resources/mock-responses/cmm_memo_retriever.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_contract_review_document.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_contract_review_history.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_contract_review_result.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_contract_review_status.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_product_coverage.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_product_info.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_product_premium_table.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_underwriting_additional_request.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_underwriting_result.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/lic_underwriting_risk_grade.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sms_cmm_claim_search.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_activity_calendar.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_activity_daily.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_activity_report_status.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_activity_summary.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_call_activity.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_customer_consulting.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_field_support_request.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_prospect_list.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_training_completion.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sof_visit_count.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_incentive_summary.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_monthly_performance.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_new_contract_count.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_performance_comparison.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_premium_performance.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_product_performance.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_sales_ranking.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_target_history.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_target_progress.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sog_target_summary.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_consent_expiry.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_consent_withdrawal.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent_scope.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_channel.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_history.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_status.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_consent.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_detail.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/sot_tm_call_eligibility.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_answer.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_category.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_detail.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_escalation.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_faq.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_list.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_manager.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_satisfaction.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_sla.json delete mode 100644 dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_status.json delete mode 100644 dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json delete mode 100644 dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCaseTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCaseTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImplTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImplTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImplTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImplTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImplTest.java delete mode 100644 dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImplTest.java diff --git a/dat-was-sal/Dockerfile b/dat-was-sal/Dockerfile index b087be906..5b9b12ab2 100644 --- a/dat-was-sal/Dockerfile +++ b/dat-was-sal/Dockerfile @@ -3,6 +3,5 @@ WORKDIR /app RUN apk add --no-cache tzdata ENV TZ=Asia/Seoul COPY dat-was-sal/build/libs/*-SNAPSHOT.jar app.jar -EXPOSE 8082 +EXPOSE 8083 ENTRYPOINT ["java", "-jar", "app.jar"] - diff --git a/dat-was-sal/build.gradle b/dat-was-sal/build.gradle index c04cf80f4..e08421661 100644 --- a/dat-was-sal/build.gradle +++ b/dat-was-sal/build.gradle @@ -1,9 +1,9 @@ plugins { - // SMS Tool Pod를 독립 실행 가능한 Spring Boot JAR로 생성합니다. + // Spring Boot 3.5.11 version is managed by the root build.gradle. id 'org.springframework.boot' } dependencies { - // MCP Server, Tool 공통 처리, MCI/EAI 연동 기반은 dat-was-lib에서 상속합니다. + // Shared MCP, Glow integration, validation, logging, Lombok and MapStruct configuration. implementation project(':dat-was-lib') } diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/ClaimSearchConverter.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/ClaimSearchConverter.java deleted file mode 100644 index 3f41a8fce..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/ClaimSearchConverter.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.converter; - -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchResponse; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io.CLCNNB00001_I; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io.CLCNNB00001_O; -import org.mapstruct.Mapper; - -@Mapper(componentModel = "spring") -public interface ClaimSearchConverter { - CLCNNB00001_I toLegacyRequest(ClaimSearchRequest request); - ClaimSearchRequest toRequest(CLCNNB00001_I mciRequest); - ClaimSearchResponse toResponse(CLCNNB00001_O mciRes); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/MemoListRetrieverConverter.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/MemoListRetrieverConverter.java deleted file mode 100644 index 889e4a494..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/converter/MemoListRetrieverConverter.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.converter; - -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverResponse; -import io.shinhanlife.dat.mcc.infra.itrf.http.memo.io.MemoListRetrieverHttpRequest; -import io.shinhanlife.dat.mcc.infra.itrf.http.memo.io.MemoListRetrieverHttpResponse; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface MemoListRetrieverConverter { - // Field names differ? Add mappings like this before the method. - // @Mapping(source = "sourceField", target = "targetField") - MemoListRetrieverHttpRequest toHttpRequest(MemoListRetrieverRequest request); - MemoListRetrieverResponse toResponse(MemoListRetrieverHttpResponse httpResponse); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchRequest.java deleted file mode 100644 index 53c285d25..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ClaimSearchRequest { - @Schema(description = "보험금 청구번호", example = "CLM202608100001", requiredMode = Schema.RequiredMode.REQUIRED) - private String claimNo; - - @Schema(description = "보험 계약번호", example = "10023456789") - private String contractNo; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchResponse.java deleted file mode 100644 index 55fbfe6e8..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/ClaimSearchResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ClaimSearchResponse { - private String resultCode; - - private String resultMessage; - @Schema(description = "청구 처리 상태 코드", example = "RECEIVED", requiredMode = Schema.RequiredMode.REQUIRED) - private String status; - - @Schema(description = "청구 처리 상태명", example = "접수", requiredMode = Schema.RequiredMode.REQUIRED) - private String statusLabel; - - @Schema(description = "승인 금액", example = "150000") - private Long approvedAmount; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverRequest.java deleted file mode 100644 index 4b39c29bf..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MemoListRetrieverRequest { - @Schema(description = "조회할 의뢰서 상태", example = "OPEN", requiredMode = Schema.RequiredMode.REQUIRED) - private String memoStatus; - - @Schema(description = "검색 키워드", example = "프로젝트", requiredMode = Schema.RequiredMode.REQUIRED) - private String searchKeyword; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverResponse.java deleted file mode 100644 index 1d3183a71..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/dto/MemoListRetrieverResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MemoListRetrieverResponse { - private String resultCode; - - private String resultMessage; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCase.java deleted file mode 100644 index ce9968f68..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCase.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase; - -import org.springaicommunity.mcp.annotation.McpTool; -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchResponse; - -/** - * @package io.shinhanlife.dat.mcc.biz.cmm.usecase - * @className ClaimSearchUseCase - * @description AX HUB 시스템 처리 클래스 - * @author jade - * @create 2026.08.10 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.08.10  jade    최초생성
- *
- * 
- */ -public interface ClaimSearchUseCase { - - @McpTool(name = "cmm_claim_search", title = "청구번호 또는 계약번호로 보험금 청구 상태를 조회한다.", description = "청구번호 또는 계약번호로 보험금 청구 상태를 조회한다.") - @GrowToolHint( - requiresApproval = false, - categoryKey = "cmm", - mappingId = "DIRECT_CMM_CLAIM_SEARCH", - functionDescription = "청구번호 또는 계약번호로 보험금 청구 상태와 심사 결과를 조회한다.", - whenToUse = "사용자가 기존 보험금 청구의 진행 상태나 지급 결과를 확인하려는 경우 사용한다.", - whenNotToUse = "보험금 청구를 새로 접수하거나 기존 청구 내용을 변경하려는 경우에는 사용하지 않는다.", - ioLimits = "청구번호 또는 계약번호 중 하나 이상이 필요하며 조회 결과만 반환한다.", - displayDescription = "보험금 청구 상태와 심사 결과를 조회합니다.", - exampleQueries = {"내 보험금 청구가 어디까지 진행됐는지 알려줘", "계약번호로 최근 청구 상태를 확인해줘", "청구 심사 결과가 나왔는지 조회해줘"}, - destructive = false, - idempotent = true, - tags = {"보험금", "청구조회"}, - ownerOrg = "MCP_TOOL" - ) - ClaimSearchResponse searchClaim(ClaimSearchRequest req); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCase.java deleted file mode 100644 index d96225a27..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCase.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase; - -import org.springaicommunity.mcp.annotation.McpTool; -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverResponse; - -/** - * @package io.shinhanlife.dat.mcc.biz.cmm.usecase - * @className MemoListRetrieverUseCase - * @description AX HUB 시스템 처리 클래스 - * @author Admin - * @create 2026.08.11 - *
- * ---------- 개정이력 ----------
- * 수정일       수정자     수정내용
- * ---------- -------- ---------------------------
- * 2026.08.11  Admin    최초생성
- *
- * 
- */ -public interface MemoListRetrieverUseCase { - - @McpTool(name = "cmm_memo_retriever", title = "의뢰서 목록 조회", description = "의뢰서 목록을 조회하여 의뢰 정보를 반환합니다.") - @GrowToolHint( - requiresApproval = false, - categoryKey = "cmm", - mappingId = "DIRECT_CMM_MEMO_RETRIEVER", - functionDescription = "상태와 검색어 조건으로 의뢰서 목록을 조회한다.", - whenToUse = "사용자가 등록된 의뢰서의 목록이나 처리 현황을 찾으려는 경우 사용한다.", - whenNotToUse = "의뢰서를 신규 등록하거나 내용을 변경하려는 경우에는 사용하지 않는다.", - ioLimits = "선택 조건에 해당하는 의뢰서 요약 목록만 반환한다.", - displayDescription = "조건에 맞는 의뢰서 목록을 조회합니다.", - exampleQueries = {"처리 중인 의뢰서를 보여줘", "지난번 계약 관련 의뢰서를 찾아줘", "완료된 의뢰서 목록을 조회해줘"}, - destructive = false, - idempotent = true, - tags = {"의뢰서", "목록조회"}, - ownerOrg = "MCP_TOOL" - ) - MemoListRetrieverResponse retrieveMemoList(MemoListRetrieverRequest req); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImpl.java deleted file mode 100644 index 801b01255..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImpl.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchResponse; -import io.shinhanlife.dat.mcc.biz.cmm.usecase.ClaimSearchUseCase; -import io.shinhanlife.glow.communication.dto.Transfer; -import io.shinhanlife.glow.BizException; -import org.springframework.stereotype.Service; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import io.shinhanlife.dat.mcc.biz.cmm.converter.ClaimSearchConverter; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io.CLCNNB00001_I; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io.CLCNNB00001_O; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.MciNclaClient; - - -/** - * @package io.shinhanlife.dat.mcc.biz.cmm.usecase.impl - * @className ClaimSearchUseCaseImpl - * @description AX HUB 시스템 처리 클래스 - * @author jade - * @create 2026.08.10 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.08.10  jade    최초생성
- *
- * 
- */ -@Slf4j -@Service -@RequiredArgsConstructor -public class ClaimSearchUseCaseImpl implements ClaimSearchUseCase { - - private final MciNclaClient mci; - private final ClaimSearchConverter converter; - - @Override - public ClaimSearchResponse searchClaim(ClaimSearchRequest req) { - log.info("[MCI Tool] {} 요청 수신.", "cmm_claim_search"); - try { - // MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO) - CLCNNB00001_I mciReq = converter.toLegacyRequest(req); - - Transfer resTransfer = mci.callTo( - "CLCNNB00001", - null, - mciReq, - CLCNNB00001_O.class - ); - ClaimSearchResponse response = new ClaimSearchResponse(); - if (resTransfer.getBody() != null) { - response = converter.toResponse(resTransfer.getBody()); - } - response.setResultCode("SUCCESS"); - response.setResultMessage(resTransfer.getBody() != null - ? "MCI call completed." - : "MCI call completed without a response body."); - return response; - } catch (BizException e) { - log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); - ClaimSearchResponse response = new ClaimSearchResponse(); - response.setResultCode("ERROR"); - response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); - return response; - } - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/MemoListRetrieverUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/MemoListRetrieverUseCaseImpl.java deleted file mode 100644 index c3b4b1cd8..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/MemoListRetrieverUseCaseImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.cmm.converter.MemoListRetrieverConverter; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverResponse; -import io.shinhanlife.dat.mcc.infra.itrf.http.memo.MemoClient; -import io.shinhanlife.dat.mcc.infra.itrf.http.memo.io.MemoListRetrieverHttpRequest; -import io.shinhanlife.dat.mcc.infra.itrf.http.memo.io.MemoListRetrieverHttpResponse; -import io.shinhanlife.dat.mcc.biz.cmm.usecase.MemoListRetrieverUseCase; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class MemoListRetrieverUseCaseImpl implements MemoListRetrieverUseCase { - - private final MemoListRetrieverConverter converter; - private final MemoClient memoClient; - - @Override - public MemoListRetrieverResponse retrieveMemoList(MemoListRetrieverRequest req) { - MemoListRetrieverHttpRequest httpRequest = converter.toHttpRequest(req); - MemoListRetrieverHttpResponse httpResponse = memoClient.call(httpRequest, MemoListRetrieverHttpResponse.class); - - MemoListRetrieverResponse response = converter.toResponse(httpResponse); - - // Sparrow NULL_RETURN (널 역참조) 방어 로직 - if (response == null) { - response = new MemoListRetrieverResponse(); - response.setResultCode("ERROR"); - response.setResultMessage("HTTP API 응답이 없거나 변환에 실패했습니다."); - return response; - } - - response.setResultCode("SUCCESS"); - response.setResultMessage("HTTP API call completed."); - return response; - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolRequest.java deleted file mode 100644 index d4a09433f..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.lic.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springaicommunity.mcp.annotation.McpToolParam; - -@Data -public class LicToolRequest { - @McpToolParam(description = "상품코드", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String productCode; - - @McpToolParam(description = "계약심사번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String contractId; - - @McpToolParam(description = "조회 기준일(YYYY-MM-DD)", required = false) - @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$") - private String queryDate; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolResponse.java deleted file mode 100644 index 695a46c8c..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/dto/LicToolResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.lic.dto; - -import java.util.List; -import lombok.Data; - -@Data -public class LicToolResponse { - private String toolName; - private String category; - private String referenceId; - private String status; - private String summary; - private String asOfDate; - private List details; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/LicUnderwritingUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/LicUnderwritingUseCase.java deleted file mode 100644 index ef6a2ce57..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/LicUnderwritingUseCase.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.lic.usecase; - -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.lic.dto.LicToolRequest; -import io.shinhanlife.dat.mcc.biz.lic.dto.LicToolResponse; -import org.springaicommunity.mcp.annotation.McpTool; - -public interface LicUnderwritingUseCase { - @McpTool(name = "lic_product_info", title = "상품 정보 조회", description = "상품 정보 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_PRODUCT_INFO", - functionDescription = "상품 정보 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 상품 정보 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "상품 정보 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"상품 정보 조회 정보를 보여줘", "상품 정보 조회 결과를 확인해줘", "현재 상품 정보 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getProductInfo(LicToolRequest request); - - @McpTool(name = "lic_product_coverage", title = "상품 보장내용 조회", description = "상품 보장내용 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_PRODUCT_COVERAGE", - functionDescription = "상품 보장내용 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 상품 보장내용 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "상품 보장내용 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"상품 보장내용 조회 정보를 보여줘", "상품 보장내용 조회 결과를 확인해줘", "현재 상품 보장내용 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getProductCoverage(LicToolRequest request); - - @McpTool(name = "lic_product_premium_table", title = "상품 보험료 요율표 조회", description = "상품 보험료 요율표 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_PRODUCT_PREMIUM_TABLE", - functionDescription = "상품 보험료 요율표 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 상품 보험료 요율표 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "상품 보험료 요율표 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"상품 보험료 요율표 조회 정보를 보여줘", "상품 보험료 요율표 조회 결과를 확인해줘", "현재 상품 보험료 요율표 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getProductPremiumTable(LicToolRequest request); - - @McpTool(name = "lic_contract_review_status", title = "계약심사 진행상태 조회", description = "계약심사 진행상태 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_CONTRACT_REVIEW_STATUS", - functionDescription = "계약심사 진행상태 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 계약심사 진행상태 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "계약심사 진행상태 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"계약심사 진행상태 조회 정보를 보여줘", "계약심사 진행상태 조회 결과를 확인해줘", "현재 계약심사 진행상태 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getContractReviewStatus(LicToolRequest request); - - @McpTool(name = "lic_contract_review_document", title = "계약심사 제출서류 현황 조회", description = "계약심사 제출서류 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_CONTRACT_REVIEW_DOCUMENT", - functionDescription = "계약심사 제출서류 현황 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 계약심사 제출서류 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "계약심사 제출서류 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"계약심사 제출서류 현황 조회 정보를 보여줘", "계약심사 제출서류 현황 조회 결과를 확인해줘", "현재 계약심사 제출서류 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getContractReviewDocument(LicToolRequest request); - - @McpTool(name = "lic_contract_review_result", title = "계약심사 결과 조회", description = "계약심사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_CONTRACT_REVIEW_RESULT", - functionDescription = "계약심사 결과 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 계약심사 결과 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "계약심사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"계약심사 결과 조회 정보를 보여줘", "계약심사 결과 조회 결과를 확인해줘", "현재 계약심사 결과 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getContractReviewResult(LicToolRequest request); - - @McpTool(name = "lic_contract_review_history", title = "계약심사 이력 조회", description = "계약심사 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_CONTRACT_REVIEW_HISTORY", - functionDescription = "계약심사 이력 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 계약심사 이력 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "계약심사 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"계약심사 이력 조회 정보를 보여줘", "계약심사 이력 조회 결과를 확인해줘", "현재 계약심사 이력 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getContractReviewHistory(LicToolRequest request); - - @McpTool(name = "lic_underwriting_result", title = "언더라이팅 인수심사 결과 조회", description = "언더라이팅 인수심사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_UNDERWRITING_RESULT", - functionDescription = "언더라이팅 인수심사 결과 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 언더라이팅 인수심사 결과 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "언더라이팅 인수심사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"언더라이팅 인수심사 결과 조회 정보를 보여줘", "언더라이팅 인수심사 결과 조회 결과를 확인해줘", "현재 언더라이팅 인수심사 결과 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getUnderwritingResult(LicToolRequest request); - - @McpTool(name = "lic_underwriting_risk_grade", title = "언더라이팅 위험등급 조회", description = "언더라이팅 위험등급 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_UNDERWRITING_RISK_GRADE", - functionDescription = "언더라이팅 위험등급 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 언더라이팅 위험등급 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "언더라이팅 위험등급 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"언더라이팅 위험등급 조회 정보를 보여줘", "언더라이팅 위험등급 조회 결과를 확인해줘", "현재 언더라이팅 위험등급 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getUnderwritingRiskGrade(LicToolRequest request); - - @McpTool(name = "lic_underwriting_additional_request", title = "언더라이팅 추가자료 요청 현황 조회", description = "언더라이팅 추가자료 요청 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "lic", - mappingId = "DIRECT_LIC_UNDERWRITING_ADDITIONAL_REQUEST", - functionDescription = "언더라이팅 추가자료 요청 현황 조회 정보를 조회합니다.", - whenToUse = "상품·계약심사 업무에서 언더라이팅 추가자료 요청 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "언더라이팅 추가자료 요청 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"언더라이팅 추가자료 요청 현황 조회 정보를 보여줘", "언더라이팅 추가자료 요청 현황 조회 결과를 확인해줘", "현재 언더라이팅 추가자료 요청 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"lic", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - LicToolResponse getUnderwritingAdditionalRequest(LicToolRequest request); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImpl.java deleted file mode 100644 index ec6811ab0..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.lic.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.lic.dto.LicToolRequest; -import io.shinhanlife.dat.mcc.biz.lic.dto.LicToolResponse; -import io.shinhanlife.dat.mcc.biz.lic.usecase.LicUnderwritingUseCase; -import java.util.List; -import org.springframework.stereotype.Service; - -@Service -public class LicUnderwritingUseCaseImpl implements LicUnderwritingUseCase { - @Override - public LicToolResponse getProductInfo(LicToolRequest request) { - return mockResponse(request, "lic_product_info", "상품 정보 조회"); - } - - @Override - public LicToolResponse getProductCoverage(LicToolRequest request) { - return mockResponse(request, "lic_product_coverage", "상품 보장내용 조회"); - } - - @Override - public LicToolResponse getProductPremiumTable(LicToolRequest request) { - return mockResponse(request, "lic_product_premium_table", "상품 보험료 요율표 조회"); - } - - @Override - public LicToolResponse getContractReviewStatus(LicToolRequest request) { - return mockResponse(request, "lic_contract_review_status", "계약심사 진행상태 조회"); - } - - @Override - public LicToolResponse getContractReviewDocument(LicToolRequest request) { - return mockResponse(request, "lic_contract_review_document", "계약심사 제출서류 현황 조회"); - } - - @Override - public LicToolResponse getContractReviewResult(LicToolRequest request) { - return mockResponse(request, "lic_contract_review_result", "계약심사 결과 조회"); - } - - @Override - public LicToolResponse getContractReviewHistory(LicToolRequest request) { - return mockResponse(request, "lic_contract_review_history", "계약심사 이력 조회"); - } - - @Override - public LicToolResponse getUnderwritingResult(LicToolRequest request) { - return mockResponse(request, "lic_underwriting_result", "언더라이팅 인수심사 결과 조회"); - } - - @Override - public LicToolResponse getUnderwritingRiskGrade(LicToolRequest request) { - return mockResponse(request, "lic_underwriting_risk_grade", "언더라이팅 위험등급 조회"); - } - - @Override - public LicToolResponse getUnderwritingAdditionalRequest(LicToolRequest request) { - return mockResponse(request, "lic_underwriting_additional_request", "언더라이팅 추가자료 요청 현황 조회"); - } - - private LicToolResponse mockResponse(LicToolRequest request, String toolName, String title) { - LicToolResponse response = new LicToolResponse(); - response.setToolName(toolName); - response.setCategory("LIC"); - response.setReferenceId(request != null && hasText(request.getProductCode()) ? request.getProductCode() - : request != null && hasText(request.getContractId()) ? request.getContractId() : "LIC-000001"); - response.setStatus("정상"); - response.setSummary(title + " 결과"); - response.setAsOfDate(request != null && hasText(request.getQueryDate()) ? request.getQueryDate() : "2026-08-14"); - response.setDetails(List.of(title + " 모의 상세정보", "외부 시스템을 변경하지 않는 조회 결과")); - return response; - } - - private boolean hasText(String value) { - return value != null && !value.isBlank(); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolRequest.java deleted file mode 100644 index d704a3b38..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sof.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springaicommunity.mcp.annotation.McpToolParam; - -@Data -public class SofToolRequest { - @McpToolParam(description = "설계사번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String agentId; - - @McpToolParam(description = "GA 조직번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String organizationId; - - @McpToolParam(description = "조회 기준일(YYYY-MM-DD)", required = false) - @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$") - private String queryDate; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolResponse.java deleted file mode 100644 index ff3bdc207..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/dto/SofToolResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sof.dto; - -import java.util.List; -import lombok.Data; - -@Data -public class SofToolResponse { - private String toolName; - private String category; - private String referenceId; - private String status; - private String summary; - private String asOfDate; - private List details; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/SofFieldActivityUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/SofFieldActivityUseCase.java deleted file mode 100644 index f138c15ac..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/SofFieldActivityUseCase.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sof.usecase; - -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.sof.dto.SofToolRequest; -import io.shinhanlife.dat.mcc.biz.sof.dto.SofToolResponse; -import org.springaicommunity.mcp.annotation.McpTool; - -public interface SofFieldActivityUseCase { - @McpTool(name = "sof_activity_daily", title = "GA 일별 활동 현황 조회", description = "GA 일별 활동 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_ACTIVITY_DAILY", - functionDescription = "GA 일별 활동 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 GA 일별 활동 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA 일별 활동 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA 일별 활동 현황 조회 정보를 보여줘", "GA 일별 활동 현황 조회 결과를 확인해줘", "현재 GA 일별 활동 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getActivityDaily(SofToolRequest request); - - @McpTool(name = "sof_visit_count", title = "고객 방문 건수 조회", description = "고객 방문 건수 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_VISIT_COUNT", - functionDescription = "고객 방문 건수 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 고객 방문 건수 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "고객 방문 건수 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"고객 방문 건수 조회 정보를 보여줘", "고객 방문 건수 조회 결과를 확인해줘", "현재 고객 방문 건수 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getVisitCount(SofToolRequest request); - - @McpTool(name = "sof_call_activity", title = "콜 활동 현황 조회", description = "콜 활동 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_CALL_ACTIVITY", - functionDescription = "콜 활동 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 콜 활동 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "콜 활동 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"콜 활동 현황 조회 정보를 보여줘", "콜 활동 현황 조회 결과를 확인해줘", "현재 콜 활동 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getCallActivity(SofToolRequest request); - - @McpTool(name = "sof_customer_consulting", title = "고객 상담 현황 조회", description = "고객 상담 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_CUSTOMER_CONSULTING", - functionDescription = "고객 상담 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 고객 상담 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "고객 상담 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"고객 상담 현황 조회 정보를 보여줘", "고객 상담 현황 조회 결과를 확인해줘", "현재 고객 상담 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getCustomerConsulting(SofToolRequest request); - - @McpTool(name = "sof_prospect_list", title = "신규 발굴 고객 목록 조회", description = "신규 발굴 고객 목록 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_PROSPECT_LIST", - functionDescription = "신규 발굴 고객 목록 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 신규 발굴 고객 목록 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "신규 발굴 고객 목록 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"신규 발굴 고객 목록 조회 정보를 보여줘", "신규 발굴 고객 목록 조회 결과를 확인해줘", "현재 신규 발굴 고객 목록 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getProspectList(SofToolRequest request); - - @McpTool(name = "sof_activity_calendar", title = "활동 일정 조회", description = "활동 일정 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_ACTIVITY_CALENDAR", - functionDescription = "활동 일정 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 활동 일정 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "활동 일정 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"활동 일정 조회 정보를 보여줘", "활동 일정 조회 결과를 확인해줘", "현재 활동 일정 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getActivityCalendar(SofToolRequest request); - - @McpTool(name = "sof_activity_report_status", title = "활동일지 제출 현황 조회", description = "활동일지 제출 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_ACTIVITY_REPORT_STATUS", - functionDescription = "활동일지 제출 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 활동일지 제출 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "활동일지 제출 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"활동일지 제출 현황 조회 정보를 보여줘", "활동일지 제출 현황 조회 결과를 확인해줘", "현재 활동일지 제출 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getActivityReportStatus(SofToolRequest request); - - @McpTool(name = "sof_training_completion", title = "교육 이수 현황 조회", description = "교육 이수 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_TRAINING_COMPLETION", - functionDescription = "교육 이수 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 교육 이수 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "교육 이수 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"교육 이수 현황 조회 정보를 보여줘", "교육 이수 현황 조회 결과를 확인해줘", "현재 교육 이수 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getTrainingCompletion(SofToolRequest request); - - @McpTool(name = "sof_field_support_request", title = "현장 지원 요청 현황 조회", description = "현장 지원 요청 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_FIELD_SUPPORT_REQUEST", - functionDescription = "현장 지원 요청 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 현장 지원 요청 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "현장 지원 요청 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"현장 지원 요청 현황 조회 정보를 보여줘", "현장 지원 요청 현황 조회 결과를 확인해줘", "현재 현장 지원 요청 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getFieldSupportRequest(SofToolRequest request); - - @McpTool(name = "sof_activity_summary", title = "GA 활동 종합 현황 조회", description = "GA 활동 종합 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sof", - mappingId = "DIRECT_SOF_ACTIVITY_SUMMARY", - functionDescription = "GA 활동 종합 현황 조회 정보를 조회합니다.", - whenToUse = "GA 활동 업무에서 GA 활동 종합 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA 활동 종합 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA 활동 종합 현황 조회 정보를 보여줘", "GA 활동 종합 현황 조회 결과를 확인해줘", "현재 GA 활동 종합 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sof", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SofToolResponse getActivitySummary(SofToolRequest request); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImpl.java deleted file mode 100644 index 8c8712819..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sof.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.sof.dto.SofToolRequest; -import io.shinhanlife.dat.mcc.biz.sof.dto.SofToolResponse; -import io.shinhanlife.dat.mcc.biz.sof.usecase.SofFieldActivityUseCase; -import java.util.List; -import org.springframework.stereotype.Service; - -@Service -public class SofFieldActivityUseCaseImpl implements SofFieldActivityUseCase { - @Override - public SofToolResponse getActivityDaily(SofToolRequest request) { - return mockResponse(request, "sof_activity_daily", "GA 일별 활동 현황 조회"); - } - - @Override - public SofToolResponse getVisitCount(SofToolRequest request) { - return mockResponse(request, "sof_visit_count", "고객 방문 건수 조회"); - } - - @Override - public SofToolResponse getCallActivity(SofToolRequest request) { - return mockResponse(request, "sof_call_activity", "콜 활동 현황 조회"); - } - - @Override - public SofToolResponse getCustomerConsulting(SofToolRequest request) { - return mockResponse(request, "sof_customer_consulting", "고객 상담 현황 조회"); - } - - @Override - public SofToolResponse getProspectList(SofToolRequest request) { - return mockResponse(request, "sof_prospect_list", "신규 발굴 고객 목록 조회"); - } - - @Override - public SofToolResponse getActivityCalendar(SofToolRequest request) { - return mockResponse(request, "sof_activity_calendar", "활동 일정 조회"); - } - - @Override - public SofToolResponse getActivityReportStatus(SofToolRequest request) { - return mockResponse(request, "sof_activity_report_status", "활동일지 제출 현황 조회"); - } - - @Override - public SofToolResponse getTrainingCompletion(SofToolRequest request) { - return mockResponse(request, "sof_training_completion", "교육 이수 현황 조회"); - } - - @Override - public SofToolResponse getFieldSupportRequest(SofToolRequest request) { - return mockResponse(request, "sof_field_support_request", "현장 지원 요청 현황 조회"); - } - - @Override - public SofToolResponse getActivitySummary(SofToolRequest request) { - return mockResponse(request, "sof_activity_summary", "GA 활동 종합 현황 조회"); - } - - private SofToolResponse mockResponse(SofToolRequest request, String toolName, String title) { - SofToolResponse response = new SofToolResponse(); - response.setToolName(toolName); - response.setCategory("SOF"); - response.setReferenceId(request != null && hasText(request.getAgentId()) ? request.getAgentId() - : request != null && hasText(request.getOrganizationId()) ? request.getOrganizationId() : "SOF-000001"); - response.setStatus("정상"); - response.setSummary(title + " 결과"); - response.setAsOfDate(request != null && hasText(request.getQueryDate()) ? request.getQueryDate() : "2026-08-14"); - response.setDetails(List.of(title + " 모의 상세정보", "외부 시스템을 변경하지 않는 조회 결과")); - return response; - } - - private boolean hasText(String value) { - return value != null && !value.isBlank(); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolRequest.java deleted file mode 100644 index a057e5e0b..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sog.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springaicommunity.mcp.annotation.McpToolParam; - -@Data -public class SogToolRequest { - @McpToolParam(description = "설계사번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String agentId; - - @McpToolParam(description = "GA 조직번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String organizationId; - - @McpToolParam(description = "조회 기준일(YYYY-MM-DD)", required = false) - @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$") - private String queryDate; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolResponse.java deleted file mode 100644 index 7b3ac4a84..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/dto/SogToolResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sog.dto; - -import java.util.List; -import lombok.Data; - -@Data -public class SogToolResponse { - private String toolName; - private String category; - private String referenceId; - private String status; - private String summary; - private String asOfDate; - private List details; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/SogSalesPerformanceUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/SogSalesPerformanceUseCase.java deleted file mode 100644 index fbf046023..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/SogSalesPerformanceUseCase.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sog.usecase; - -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.sog.dto.SogToolRequest; -import io.shinhanlife.dat.mcc.biz.sog.dto.SogToolResponse; -import org.springaicommunity.mcp.annotation.McpTool; - -public interface SogSalesPerformanceUseCase { - @McpTool(name = "sog_target_summary", title = "GA 개인별 영업목표 요약 조회", description = "GA 개인별 영업목표 요약 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_TARGET_SUMMARY", - functionDescription = "GA 개인별 영업목표 요약 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 GA 개인별 영업목표 요약 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA 개인별 영업목표 요약 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA 개인별 영업목표 요약 조회 정보를 보여줘", "GA 개인별 영업목표 요약 조회 결과를 확인해줘", "현재 GA 개인별 영업목표 요약 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getTargetSummary(SogToolRequest request); - - @McpTool(name = "sog_target_progress", title = "영업목표 달성률 조회", description = "영업목표 달성률 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_TARGET_PROGRESS", - functionDescription = "영업목표 달성률 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 영업목표 달성률 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "영업목표 달성률 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"영업목표 달성률 조회 정보를 보여줘", "영업목표 달성률 조회 결과를 확인해줘", "현재 영업목표 달성률 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getTargetProgress(SogToolRequest request); - - @McpTool(name = "sog_monthly_performance", title = "GA 월별 실적 조회", description = "GA 월별 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_MONTHLY_PERFORMANCE", - functionDescription = "GA 월별 실적 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 GA 월별 실적 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA 월별 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA 월별 실적 조회 정보를 보여줘", "GA 월별 실적 조회 결과를 확인해줘", "현재 GA 월별 실적 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getMonthlyPerformance(SogToolRequest request); - - @McpTool(name = "sog_product_performance", title = "상품별 실적 조회", description = "상품별 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_PRODUCT_PERFORMANCE", - functionDescription = "상품별 실적 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 상품별 실적 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "상품별 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"상품별 실적 조회 정보를 보여줘", "상품별 실적 조회 결과를 확인해줘", "현재 상품별 실적 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getProductPerformance(SogToolRequest request); - - @McpTool(name = "sog_new_contract_count", title = "신계약 건수 실적 조회", description = "신계약 건수 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_NEW_CONTRACT_COUNT", - functionDescription = "신계약 건수 실적 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 신계약 건수 실적 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "신계약 건수 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"신계약 건수 실적 조회 정보를 보여줘", "신계약 건수 실적 조회 결과를 확인해줘", "현재 신계약 건수 실적 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getNewContractCount(SogToolRequest request); - - @McpTool(name = "sog_premium_performance", title = "보험료 실적 조회", description = "보험료 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_PREMIUM_PERFORMANCE", - functionDescription = "보험료 실적 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 보험료 실적 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "보험료 실적 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"보험료 실적 조회 정보를 보여줘", "보험료 실적 조회 결과를 확인해줘", "현재 보험료 실적 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getPremiumPerformance(SogToolRequest request); - - @McpTool(name = "sog_sales_ranking", title = "GA 영업 순위 조회", description = "GA 영업 순위 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_SALES_RANKING", - functionDescription = "GA 영업 순위 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 GA 영업 순위 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA 영업 순위 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA 영업 순위 조회 정보를 보여줘", "GA 영업 순위 조회 결과를 확인해줘", "현재 GA 영업 순위 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getSalesRanking(SogToolRequest request); - - @McpTool(name = "sog_incentive_summary", title = "영업 인센티브 요약 조회", description = "영업 인센티브 요약 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_INCENTIVE_SUMMARY", - functionDescription = "영업 인센티브 요약 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 영업 인센티브 요약 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "영업 인센티브 요약 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"영업 인센티브 요약 조회 정보를 보여줘", "영업 인센티브 요약 조회 결과를 확인해줘", "현재 영업 인센티브 요약 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getIncentiveSummary(SogToolRequest request); - - @McpTool(name = "sog_target_history", title = "영업목표 변경 이력 조회", description = "영업목표 변경 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_TARGET_HISTORY", - functionDescription = "영업목표 변경 이력 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 영업목표 변경 이력 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "영업목표 변경 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"영업목표 변경 이력 조회 정보를 보여줘", "영업목표 변경 이력 조회 결과를 확인해줘", "현재 영업목표 변경 이력 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getTargetHistory(SogToolRequest request); - - @McpTool(name = "sog_performance_comparison", title = "전년 동기 대비 실적 비교 조회", description = "전년 동기 대비 실적 비교 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sog", - mappingId = "DIRECT_SOG_PERFORMANCE_COMPARISON", - functionDescription = "전년 동기 대비 실적 비교 조회 정보를 조회합니다.", - whenToUse = "GA 영업 업무에서 전년 동기 대비 실적 비교 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "전년 동기 대비 실적 비교 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"전년 동기 대비 실적 비교 조회 정보를 보여줘", "전년 동기 대비 실적 비교 조회 결과를 확인해줘", "현재 전년 동기 대비 실적 비교 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sog", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SogToolResponse getPerformanceComparison(SogToolRequest request); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImpl.java deleted file mode 100644 index 5fc07cb9b..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sog.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.sog.dto.SogToolRequest; -import io.shinhanlife.dat.mcc.biz.sog.dto.SogToolResponse; -import io.shinhanlife.dat.mcc.biz.sog.usecase.SogSalesPerformanceUseCase; -import java.util.List; -import org.springframework.stereotype.Service; - -@Service -public class SogSalesPerformanceUseCaseImpl implements SogSalesPerformanceUseCase { - @Override - public SogToolResponse getTargetSummary(SogToolRequest request) { - return mockResponse(request, "sog_target_summary", "GA 개인별 영업목표 요약 조회"); - } - - @Override - public SogToolResponse getTargetProgress(SogToolRequest request) { - return mockResponse(request, "sog_target_progress", "영업목표 달성률 조회"); - } - - @Override - public SogToolResponse getMonthlyPerformance(SogToolRequest request) { - return mockResponse(request, "sog_monthly_performance", "GA 월별 실적 조회"); - } - - @Override - public SogToolResponse getProductPerformance(SogToolRequest request) { - return mockResponse(request, "sog_product_performance", "상품별 실적 조회"); - } - - @Override - public SogToolResponse getNewContractCount(SogToolRequest request) { - return mockResponse(request, "sog_new_contract_count", "신계약 건수 실적 조회"); - } - - @Override - public SogToolResponse getPremiumPerformance(SogToolRequest request) { - return mockResponse(request, "sog_premium_performance", "보험료 실적 조회"); - } - - @Override - public SogToolResponse getSalesRanking(SogToolRequest request) { - return mockResponse(request, "sog_sales_ranking", "GA 영업 순위 조회"); - } - - @Override - public SogToolResponse getIncentiveSummary(SogToolRequest request) { - return mockResponse(request, "sog_incentive_summary", "영업 인센티브 요약 조회"); - } - - @Override - public SogToolResponse getTargetHistory(SogToolRequest request) { - return mockResponse(request, "sog_target_history", "영업목표 변경 이력 조회"); - } - - @Override - public SogToolResponse getPerformanceComparison(SogToolRequest request) { - return mockResponse(request, "sog_performance_comparison", "전년 동기 대비 실적 비교 조회"); - } - - private SogToolResponse mockResponse(SogToolRequest request, String toolName, String title) { - SogToolResponse response = new SogToolResponse(); - response.setToolName(toolName); - response.setCategory("SOG"); - response.setReferenceId(request != null && hasText(request.getAgentId()) ? request.getAgentId() - : request != null && hasText(request.getOrganizationId()) ? request.getOrganizationId() : "SOG-000001"); - response.setStatus("정상"); - response.setSummary(title + " 결과"); - response.setAsOfDate(request != null && hasText(request.getQueryDate()) ? request.getQueryDate() : "2026-08-14"); - response.setDetails(List.of(title + " 모의 상세정보", "외부 시스템을 변경하지 않는 조회 결과")); - return response; - } - - private boolean hasText(String value) { - return value != null && !value.isBlank(); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolRequest.java deleted file mode 100644 index 5e0bc6983..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sot.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springaicommunity.mcp.annotation.McpToolParam; - -@Data -public class SotToolRequest { - @McpToolParam(description = "고객번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String customerId; - - @McpToolParam(description = "가입설계번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String contractId; - - @McpToolParam(description = "조회 기준일(YYYY-MM-DD)", required = false) - @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$") - private String queryDate; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolResponse.java deleted file mode 100644 index e73159972..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/dto/SotToolResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sot.dto; - -import java.util.List; -import lombok.Data; - -@Data -public class SotToolResponse { - private String toolName; - private String category; - private String referenceId; - private String status; - private String summary; - private String asOfDate; - private List details; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/SotConsentUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/SotConsentUseCase.java deleted file mode 100644 index 015620c08..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/SotConsentUseCase.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sot.usecase; - -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.sot.dto.SotToolRequest; -import io.shinhanlife.dat.mcc.biz.sot.dto.SotToolResponse; -import org.springaicommunity.mcp.annotation.McpTool; - -public interface SotConsentUseCase { - @McpTool(name = "sot_marketing_consent_status", title = "마케팅 수신동의 현황 조회", description = "마케팅 수신동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_MARKETING_CONSENT_STATUS", - functionDescription = "마케팅 수신동의 현황 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 마케팅 수신동의 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "마케팅 수신동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"마케팅 수신동의 현황 조회 정보를 보여줘", "마케팅 수신동의 현황 조회 결과를 확인해줘", "현재 마케팅 수신동의 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getMarketingConsentStatus(SotToolRequest request); - - @McpTool(name = "sot_marketing_consent_history", title = "마케팅 동의 이력 조회", description = "마케팅 동의 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_MARKETING_CONSENT_HISTORY", - functionDescription = "마케팅 동의 이력 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 마케팅 동의 이력 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "마케팅 동의 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"마케팅 동의 이력 조회 정보를 보여줘", "마케팅 동의 이력 조회 결과를 확인해줘", "현재 마케팅 동의 이력 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getMarketingConsentHistory(SotToolRequest request); - - @McpTool(name = "sot_marketing_consent_channel", title = "채널별 마케팅 동의 현황 조회", description = "채널별 마케팅 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_MARKETING_CONSENT_CHANNEL", - functionDescription = "채널별 마케팅 동의 현황 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 채널별 마케팅 동의 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "채널별 마케팅 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"채널별 마케팅 동의 현황 조회 정보를 보여줘", "채널별 마케팅 동의 현황 조회 결과를 확인해줘", "현재 채널별 마케팅 동의 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getMarketingConsentChannel(SotToolRequest request); - - @McpTool(name = "sot_subscription_design_consent", title = "가입설계 동의 현황 조회", description = "가입설계 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_SUBSCRIPTION_DESIGN_CONSENT", - functionDescription = "가입설계 동의 현황 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 가입설계 동의 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "가입설계 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"가입설계 동의 현황 조회 정보를 보여줘", "가입설계 동의 현황 조회 결과를 확인해줘", "현재 가입설계 동의 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getSubscriptionDesignConsent(SotToolRequest request); - - @McpTool(name = "sot_subscription_design_detail", title = "가입설계 동의 상세 조회", description = "가입설계 동의 상세 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_SUBSCRIPTION_DESIGN_DETAIL", - functionDescription = "가입설계 동의 상세 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 가입설계 동의 상세 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "가입설계 동의 상세 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"가입설계 동의 상세 조회 정보를 보여줘", "가입설계 동의 상세 조회 결과를 확인해줘", "현재 가입설계 동의 상세 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getSubscriptionDesignDetail(SotToolRequest request); - - @McpTool(name = "sot_customer_info_consent", title = "고객정보 수집·이용 동의 현황 조회", description = "고객정보 수집·이용 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_CUSTOMER_INFO_CONSENT", - functionDescription = "고객정보 수집·이용 동의 현황 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 고객정보 수집·이용 동의 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "고객정보 수집·이용 동의 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"고객정보 수집·이용 동의 현황 조회 정보를 보여줘", "고객정보 수집·이용 동의 현황 조회 결과를 확인해줘", "현재 고객정보 수집·이용 동의 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getCustomerInfoConsent(SotToolRequest request); - - @McpTool(name = "sot_customer_info_consent_scope", title = "고객정보 동의 범위 조회", description = "고객정보 동의 범위 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_CUSTOMER_INFO_CONSENT_SCOPE", - functionDescription = "고객정보 동의 범위 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 고객정보 동의 범위 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "고객정보 동의 범위 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"고객정보 동의 범위 조회 정보를 보여줘", "고객정보 동의 범위 조회 결과를 확인해줘", "현재 고객정보 동의 범위 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getCustomerInfoConsentScope(SotToolRequest request); - - @McpTool(name = "sot_consent_expiry", title = "동의 유효기간 만료 현황 조회", description = "동의 유효기간 만료 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_CONSENT_EXPIRY", - functionDescription = "동의 유효기간 만료 현황 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 동의 유효기간 만료 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "동의 유효기간 만료 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"동의 유효기간 만료 현황 조회 정보를 보여줘", "동의 유효기간 만료 현황 조회 결과를 확인해줘", "현재 동의 유효기간 만료 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getConsentExpiry(SotToolRequest request); - - @McpTool(name = "sot_consent_withdrawal", title = "동의 철회 이력 조회", description = "동의 철회 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_CONSENT_WITHDRAWAL", - functionDescription = "동의 철회 이력 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 동의 철회 이력 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "동의 철회 이력 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"동의 철회 이력 조회 정보를 보여줘", "동의 철회 이력 조회 결과를 확인해줘", "현재 동의 철회 이력 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getConsentWithdrawal(SotToolRequest request); - - @McpTool(name = "sot_tm_call_eligibility", title = "텔레마케팅 콜 가능여부 종합 조회", description = "텔레마케팅 콜 가능여부 종합 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "sot", - mappingId = "DIRECT_SOT_TM_CALL_ELIGIBILITY", - functionDescription = "텔레마케팅 콜 가능여부 종합 조회 정보를 조회합니다.", - whenToUse = "텔레마케팅 동의 업무에서 텔레마케팅 콜 가능여부 종합 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "텔레마케팅 콜 가능여부 종합 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"텔레마케팅 콜 가능여부 종합 조회 정보를 보여줘", "텔레마케팅 콜 가능여부 종합 조회 결과를 확인해줘", "현재 텔레마케팅 콜 가능여부 종합 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"sot", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SotToolResponse getTmCallEligibility(SotToolRequest request); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImpl.java deleted file mode 100644 index c9590436f..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sot.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.sot.dto.SotToolRequest; -import io.shinhanlife.dat.mcc.biz.sot.dto.SotToolResponse; -import io.shinhanlife.dat.mcc.biz.sot.usecase.SotConsentUseCase; -import java.util.List; -import org.springframework.stereotype.Service; - -@Service -public class SotConsentUseCaseImpl implements SotConsentUseCase { - @Override - public SotToolResponse getMarketingConsentStatus(SotToolRequest request) { - return mockResponse(request, "sot_marketing_consent_status", "마케팅 수신동의 현황 조회"); - } - - @Override - public SotToolResponse getMarketingConsentHistory(SotToolRequest request) { - return mockResponse(request, "sot_marketing_consent_history", "마케팅 동의 이력 조회"); - } - - @Override - public SotToolResponse getMarketingConsentChannel(SotToolRequest request) { - return mockResponse(request, "sot_marketing_consent_channel", "채널별 마케팅 동의 현황 조회"); - } - - @Override - public SotToolResponse getSubscriptionDesignConsent(SotToolRequest request) { - return mockResponse(request, "sot_subscription_design_consent", "가입설계 동의 현황 조회"); - } - - @Override - public SotToolResponse getSubscriptionDesignDetail(SotToolRequest request) { - return mockResponse(request, "sot_subscription_design_detail", "가입설계 동의 상세 조회"); - } - - @Override - public SotToolResponse getCustomerInfoConsent(SotToolRequest request) { - return mockResponse(request, "sot_customer_info_consent", "고객정보 수집·이용 동의 현황 조회"); - } - - @Override - public SotToolResponse getCustomerInfoConsentScope(SotToolRequest request) { - return mockResponse(request, "sot_customer_info_consent_scope", "고객정보 동의 범위 조회"); - } - - @Override - public SotToolResponse getConsentExpiry(SotToolRequest request) { - return mockResponse(request, "sot_consent_expiry", "동의 유효기간 만료 현황 조회"); - } - - @Override - public SotToolResponse getConsentWithdrawal(SotToolRequest request) { - return mockResponse(request, "sot_consent_withdrawal", "동의 철회 이력 조회"); - } - - @Override - public SotToolResponse getTmCallEligibility(SotToolRequest request) { - return mockResponse(request, "sot_tm_call_eligibility", "텔레마케팅 콜 가능여부 종합 조회"); - } - - private SotToolResponse mockResponse(SotToolRequest request, String toolName, String title) { - SotToolResponse response = new SotToolResponse(); - response.setToolName(toolName); - response.setCategory("SOT"); - response.setReferenceId(request != null && hasText(request.getCustomerId()) ? request.getCustomerId() - : request != null && hasText(request.getContractId()) ? request.getContractId() : "SOT-000001"); - response.setStatus("정상"); - response.setSummary(title + " 결과"); - response.setAsOfDate(request != null && hasText(request.getQueryDate()) ? request.getQueryDate() : "2026-08-14"); - response.setDetails(List.of(title + " 모의 상세정보", "외부 시스템을 변경하지 않는 조회 결과")); - return response; - } - - private boolean hasText(String value) { - return value != null && !value.isBlank(); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolRequest.java deleted file mode 100644 index f5fcd3828..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.spr.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springaicommunity.mcp.annotation.McpToolParam; - -@Data -public class SprToolRequest { - @McpToolParam(description = "현장문의번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String inquiryId; - - @McpToolParam(description = "설계사번호", required = false) - @Schema(pattern = "^[A-Za-z0-9_-]{3,30}$") - private String agentId; - - @McpToolParam(description = "조회 기준일(YYYY-MM-DD)", required = false) - @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$") - private String queryDate; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolResponse.java deleted file mode 100644 index 7190eaf2f..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/dto/SprToolResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.spr.dto; - -import java.util.List; -import lombok.Data; - -@Data -public class SprToolResponse { - private String toolName; - private String category; - private String referenceId; - private String status; - private String summary; - private String asOfDate; - private List details; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/SprFieldInquiryUseCase.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/SprFieldInquiryUseCase.java deleted file mode 100644 index bdab584be..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/SprFieldInquiryUseCase.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.spr.usecase; - -import io.shinhanlife.dat.lib.annotation.GrowToolHint; -import io.shinhanlife.dat.mcc.biz.spr.dto.SprToolRequest; -import io.shinhanlife.dat.mcc.biz.spr.dto.SprToolResponse; -import org.springaicommunity.mcp.annotation.McpTool; - -public interface SprFieldInquiryUseCase { - @McpTool(name = "spr_field_inquiry_list", title = "GA현장문의 목록 조회", description = "GA현장문의 목록 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_LIST", - functionDescription = "GA현장문의 목록 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 GA현장문의 목록 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA현장문의 목록 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA현장문의 목록 조회 정보를 보여줘", "GA현장문의 목록 조회 결과를 확인해줘", "현재 GA현장문의 목록 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryList(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_detail", title = "GA현장문의 상세 조회", description = "GA현장문의 상세 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_DETAIL", - functionDescription = "GA현장문의 상세 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 GA현장문의 상세 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "GA현장문의 상세 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"GA현장문의 상세 조회 정보를 보여줘", "GA현장문의 상세 조회 결과를 확인해줘", "현재 GA현장문의 상세 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryDetail(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_status", title = "문의 처리상태 조회", description = "문의 처리상태 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_STATUS", - functionDescription = "문의 처리상태 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 문의 처리상태 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "문의 처리상태 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"문의 처리상태 조회 정보를 보여줘", "문의 처리상태 조회 결과를 확인해줘", "현재 문의 처리상태 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryStatus(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_category", title = "문의 유형별 통계 조회", description = "문의 유형별 통계 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_CATEGORY", - functionDescription = "문의 유형별 통계 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 문의 유형별 통계 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "문의 유형별 통계 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"문의 유형별 통계 조회 정보를 보여줘", "문의 유형별 통계 조회 결과를 확인해줘", "현재 문의 유형별 통계 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryCategory(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_answer", title = "문의 답변 조회", description = "문의 답변 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_ANSWER", - functionDescription = "문의 답변 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 문의 답변 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "문의 답변 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"문의 답변 조회 정보를 보여줘", "문의 답변 조회 결과를 확인해줘", "현재 문의 답변 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryAnswer(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_escalation", title = "에스컬레이션 현황 조회", description = "에스컬레이션 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_ESCALATION", - functionDescription = "에스컬레이션 현황 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 에스컬레이션 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "에스컬레이션 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"에스컬레이션 현황 조회 정보를 보여줘", "에스컬레이션 현황 조회 결과를 확인해줘", "현재 에스컬레이션 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryEscalation(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_faq", title = "자주묻는질문 FAQ 조회", description = "자주묻는질문 FAQ 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_FAQ", - functionDescription = "자주묻는질문 FAQ 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 자주묻는질문 FAQ 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "자주묻는질문 FAQ 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"자주묻는질문 FAQ 조회 정보를 보여줘", "자주묻는질문 FAQ 조회 결과를 확인해줘", "현재 자주묻는질문 FAQ 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryFaq(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_manager", title = "담당자 배정 현황 조회", description = "담당자 배정 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_MANAGER", - functionDescription = "담당자 배정 현황 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 담당자 배정 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "담당자 배정 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"담당자 배정 현황 조회 정보를 보여줘", "담당자 배정 현황 조회 결과를 확인해줘", "현재 담당자 배정 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquiryManager(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_sla", title = "처리기한 SLA 현황 조회", description = "처리기한 SLA 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_SLA", - functionDescription = "처리기한 SLA 현황 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 처리기한 SLA 현황 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "처리기한 SLA 현황 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"처리기한 SLA 현황 조회 정보를 보여줘", "처리기한 SLA 현황 조회 결과를 확인해줘", "현재 처리기한 SLA 현황 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquirySla(SprToolRequest request); - - @McpTool(name = "spr_field_inquiry_satisfaction", title = "문의 만족도 조사 결과 조회", description = "문의 만족도 조사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - annotations = @McpTool.McpAnnotations(openWorldHint = false)) - @GrowToolHint( - requiresApproval = false, - categoryKey = "spr", - mappingId = "DIRECT_SPR_FIELD_INQUIRY_SATISFACTION", - functionDescription = "문의 만족도 조사 결과 조회 정보를 조회합니다.", - whenToUse = "GA현장지원 업무에서 문의 만족도 조사 결과 조회 정보가 필요할 때 사용합니다.", - whenNotToUse = "정보 변경, 승인 또는 실제 업무처리에는 사용하지 않습니다.", - ioLimits = "입력 식별자에 대한 모의 조회 데이터만 반환하며 외부 시스템을 변경하지 않습니다.", - displayDescription = "문의 만족도 조사 결과 조회 정보를 안전한 모의 데이터로 제공합니다.", - exampleQueries = {"문의 만족도 조사 결과 조회 정보를 보여줘", "문의 만족도 조사 결과 조회 결과를 확인해줘", "현재 문의 만족도 조사 결과 조회 내용을 알려줘"}, - destructive = false, - idempotent = true, - tags = {"spr", "조회", "mock"}, - ownerOrg = "MCP_TOOL" - ) - SprToolResponse getFieldInquirySatisfaction(SprToolRequest request); -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImpl.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImpl.java deleted file mode 100644 index db5439d0e..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.spr.usecase.impl; - -import io.shinhanlife.dat.mcc.biz.spr.dto.SprToolRequest; -import io.shinhanlife.dat.mcc.biz.spr.dto.SprToolResponse; -import io.shinhanlife.dat.mcc.biz.spr.usecase.SprFieldInquiryUseCase; -import java.util.List; -import org.springframework.stereotype.Service; - -@Service -public class SprFieldInquiryUseCaseImpl implements SprFieldInquiryUseCase { - @Override - public SprToolResponse getFieldInquiryList(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_list", "GA현장문의 목록 조회"); - } - - @Override - public SprToolResponse getFieldInquiryDetail(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_detail", "GA현장문의 상세 조회"); - } - - @Override - public SprToolResponse getFieldInquiryStatus(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_status", "문의 처리상태 조회"); - } - - @Override - public SprToolResponse getFieldInquiryCategory(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_category", "문의 유형별 통계 조회"); - } - - @Override - public SprToolResponse getFieldInquiryAnswer(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_answer", "문의 답변 조회"); - } - - @Override - public SprToolResponse getFieldInquiryEscalation(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_escalation", "에스컬레이션 현황 조회"); - } - - @Override - public SprToolResponse getFieldInquiryFaq(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_faq", "자주묻는질문 FAQ 조회"); - } - - @Override - public SprToolResponse getFieldInquiryManager(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_manager", "담당자 배정 현황 조회"); - } - - @Override - public SprToolResponse getFieldInquirySla(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_sla", "처리기한 SLA 현황 조회"); - } - - @Override - public SprToolResponse getFieldInquirySatisfaction(SprToolRequest request) { - return mockResponse(request, "spr_field_inquiry_satisfaction", "문의 만족도 조사 결과 조회"); - } - - private SprToolResponse mockResponse(SprToolRequest request, String toolName, String title) { - SprToolResponse response = new SprToolResponse(); - response.setToolName(toolName); - response.setCategory("SPR"); - response.setReferenceId(request != null && hasText(request.getInquiryId()) ? request.getInquiryId() - : request != null && hasText(request.getAgentId()) ? request.getAgentId() : "SPR-000001"); - response.setStatus("정상"); - response.setSummary(title + " 결과"); - response.setAsOfDate(request != null && hasText(request.getQueryDate()) ? request.getQueryDate() : "2026-08-14"); - response.setDetails(List.of(title + " 모의 상세정보", "외부 시스템을 변경하지 않는 조회 결과")); - return response; - } - - private boolean hasText(String value) { - return value != null && !value.isBlank(); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/MemoClient.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/MemoClient.java deleted file mode 100644 index dfd0ac2d8..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/MemoClient.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.http.memo; - -import io.shinhanlife.dat.lib.integration.http.component.AxhubHttpComponent; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class MemoClient { - private static final String API_NAME = "memo"; - - private final AxhubHttpComponent http; - - public O call(I request, Class responseType) { - return http.call(API_NAME, request, responseType); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpRequest.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpRequest.java deleted file mode 100644 index 475856124..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.http.memo.io; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MemoListRetrieverHttpRequest { - @Schema(description = "조회할 의뢰서 상태", example = "OPEN", requiredMode = Schema.RequiredMode.REQUIRED) - private String memoStatus; - - @Schema(description = "검색 키워드", example = "프로젝트", requiredMode = Schema.RequiredMode.REQUIRED) - private String searchKeyword; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpResponse.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpResponse.java deleted file mode 100644 index 983f7afbe..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/http/memo/io/MemoListRetrieverHttpResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.http.memo.io; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MemoListRetrieverHttpResponse { - private String resultCode; - - private String resultMessage; -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/MciNclaClient.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/MciNclaClient.java deleted file mode 100644 index 6bac3b0c6..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/MciNclaClient.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.mci.ncla; - -import org.springframework.stereotype.Component; -import lombok.RequiredArgsConstructor; -import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent; -import io.shinhanlife.glow.communication.dto.Transfer; - -/** - * @package io.shinhanlife.dat.mcc.infra.itrf.mci.ncla - * @className MciNclaClient - * @description AX HUB 시스템 처리 클래스 - * @author jade - * @create 2026.08.10 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.08.10  jade    최초생성
- *
- * 
- */ -@Component -@RequiredArgsConstructor -public class MciNclaClient { - private final AxhubMciComponent mci; - - public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) { - return mci.callTo(interfaceId, dummy, mciReq, resType); - } -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_I.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_I.java deleted file mode 100644 index ef6b436d9..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_I.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -public class CLCNNB00001_I { - @Schema(description = "보험금 청구번호", example = "CLM202608100001", requiredMode = Schema.RequiredMode.REQUIRED) - private String claimNo; - - @Schema(description = "보험 계약번호", example = "10023456789") - private String contractNo; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_O.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_O.java deleted file mode 100644 index e81ba4aca..000000000 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/infra/itrf/mci/ncla/io/CLCNNB00001_O.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -public class CLCNNB00001_O { - @Schema(description = "청구 처리 상태 코드", example = "RECEIVED", requiredMode = Schema.RequiredMode.REQUIRED) - private String status; - - @Schema(description = "청구 처리 상태명", example = "접수", requiredMode = Schema.RequiredMode.REQUIRED) - private String statusLabel; - - @Schema(description = "승인 금액", example = "150000") - private Long approvedAmount; - -} diff --git a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/sal/DatWasSalApplication.java b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/sal/DatWasSalApplication.java index 00d40003e..8730bf839 100644 --- a/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/sal/DatWasSalApplication.java +++ b/dat-was-sal/src/main/java/io/shinhanlife/dat/mcc/sal/DatWasSalApplication.java @@ -1,31 +1,27 @@ package io.shinhanlife.dat.mcc.sal; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.cache.annotation.EnableCaching; /** * @package io.shinhanlife.dat.mcc.sal * @className DatWasSalApplication * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 + * @author jade + * @create 2026.09.08 *
  * ---------- 개정이력 ----------
  * 수정일      수정자    수정내용
  * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
+ * 2026.09.08  jade    최초생성
+ *
  * 
*/ -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Import; -import io.shinhanlife.dat.lib.mcp.ToolMcpServerConfiguration; - @SpringBootApplication(scanBasePackages = {"io.shinhanlife.dat.mcc", "io.shinhanlife.dat.lib"}) @ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dat.mcc", "io.shinhanlife.dat.lib"}) @EnableCaching -@Import(ToolMcpServerConfiguration.class) public class DatWasSalApplication { public static void main(String[] args) { SpringApplication.run(DatWasSalApplication.class, args); diff --git a/dat-was-sal/src/main/resources/application-dev.yml b/dat-was-sal/src/main/resources/application-dev.yml index 6aed956e9..7fd673f5b 100644 --- a/dat-was-sal/src/main/resources/application-dev.yml +++ b/dat-was-sal/src/main/resources/application-dev.yml @@ -1,15 +1,11 @@ -# OCI 클라우드 개발 환경 전용 설정 server: - port: ${PORT:8082} - -axhub: - gateway: - url: https://axhubmcp.devjun.net + port: ${PORT:8083} spring: config: activate: on-profile: dev import: + - classpath:application-core-dev.yml - classpath:glow/application-glow.yml - classpath:glow/application-glow-dev.yml diff --git a/dat-was-sal/src/main/resources/application-local.yml b/dat-was-sal/src/main/resources/application-local.yml index 6f71fa089..d985a21ec 100644 --- a/dat-was-sal/src/main/resources/application-local.yml +++ b/dat-was-sal/src/main/resources/application-local.yml @@ -1,4 +1,3 @@ -# Local 환경 전용 설정 (H2 메모리 DB 등) spring: config: activate: @@ -6,7 +5,3 @@ spring: import: - classpath:glow/application-glow.yml - classpath:glow/application-glow-local.yml - -axhub: - tool: - url: ${AXHUB_TOOL_URL:http://localhost:${server.port}} diff --git a/dat-was-sal/src/main/resources/application-prod.yml b/dat-was-sal/src/main/resources/application-prod.yml index 8d6f1ab04..31306c3fe 100644 --- a/dat-was-sal/src/main/resources/application-prod.yml +++ b/dat-was-sal/src/main/resources/application-prod.yml @@ -1,16 +1,11 @@ server: - port: ${PORT:8082} + port: ${PORT:8083} spring: config: activate: on-profile: prod import: + - classpath:application-core-prod.yml - classpath:glow/application-glow.yml - classpath:glow/application-glow-prod.yml - -axhub: - gateway: - url: ${AXHUB_GATEWAY_URL} - tool: - url: ${AXHUB_TOOL_URL} \ No newline at end of file diff --git a/dat-was-sal/src/main/resources/application-test.yml b/dat-was-sal/src/main/resources/application-test.yml index a394e88df..1ce9d5ad4 100644 --- a/dat-was-sal/src/main/resources/application-test.yml +++ b/dat-was-sal/src/main/resources/application-test.yml @@ -1,16 +1,11 @@ server: - port: ${PORT:8082} + port: ${PORT:8083} spring: config: activate: on-profile: test import: + - classpath:application-core-test.yml - classpath:glow/application-glow.yml - classpath:glow/application-glow-test.yml - -axhub: - gateway: - url: ${AXHUB_GATEWAY_URL} - tool: - url: ${AXHUB_TOOL_URL} \ No newline at end of file diff --git a/dat-was-sal/src/main/resources/application.yml b/dat-was-sal/src/main/resources/application.yml index 5b53d9746..d0cedef0a 100644 --- a/dat-was-sal/src/main/resources/application.yml +++ b/dat-was-sal/src/main/resources/application.yml @@ -1,5 +1,5 @@ server: - port: 8082 + port: 8083 spring: application: name: dat-was-sal @@ -13,8 +13,7 @@ logging: mcp: namespace: "" manifest: - bundle-id: was-sal - # Set the AA-assigned prefix before MCP pull activation (for example: sal.). + bundle-id: dat-was-sal name-prefix: "" security: api-key: ${TOOL_SERVER_API_KEY:tool-server-key} diff --git a/dat-was-sal/src/main/resources/logback-spring.xml b/dat-was-sal/src/main/resources/logback-spring.xml index eda389e1a..46a102842 100644 --- a/dat-was-sal/src/main/resources/logback-spring.xml +++ b/dat-was-sal/src/main/resources/logback-spring.xml @@ -1,41 +1,24 @@ - - - - ${LOG_PATTERN} - - - - - - /swlog/dat-was-sal/A01/${HOSTNAME}_A01.log - - - /swlog/dat-was-sal/A01/${HOSTNAME}_A01_%d{yyyyMMdd}.%i.log - - 100MB + logs/dat-was-sal.log + + logs/dat-was-sal-%d{yyyy-MM-dd}.log 30 - 1GB ${LOG_PATTERN} - - - - diff --git a/dat-was-sal/src/main/resources/mock-responses/cmm_memo_retriever.json b/dat-was-sal/src/main/resources/mock-responses/cmm_memo_retriever.json deleted file mode 100644 index a949502b1..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/cmm_memo_retriever.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "resultCode": "SUCCESS" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_document.json b/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_document.json deleted file mode 100644 index 99650ca3a..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_document.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_contract_review_document\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"계약심사 제출서류 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"계약심사 제출서류 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_history.json b/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_history.json deleted file mode 100644 index bf49c60e4..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_history.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_contract_review_history\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"계약심사 이력 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"계약심사 이력 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_result.json b/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_result.json deleted file mode 100644 index 2020e2bd6..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_contract_review_result\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"계약심사 결과 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"계약심사 결과 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_status.json b/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_status.json deleted file mode 100644 index f813199df..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_contract_review_status.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_contract_review_status\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"계약심사 진행상태 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"계약심사 진행상태 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_product_coverage.json b/dat-was-sal/src/main/resources/mock-responses/lic_product_coverage.json deleted file mode 100644 index 9e1d63c64..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_product_coverage.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_product_coverage\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"상품 보장내용 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"상품 보장내용 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_product_info.json b/dat-was-sal/src/main/resources/mock-responses/lic_product_info.json deleted file mode 100644 index fbb220f73..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_product_info.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_product_info\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"상품 정보 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"상품 정보 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_product_premium_table.json b/dat-was-sal/src/main/resources/mock-responses/lic_product_premium_table.json deleted file mode 100644 index ea30062ec..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_product_premium_table.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_product_premium_table\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"상품 보험료 요율표 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"상품 보험료 요율표 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_additional_request.json b/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_additional_request.json deleted file mode 100644 index 3bf048d43..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_additional_request.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_underwriting_additional_request\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"언더라이팅 추가자료 요청 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"언더라이팅 추가자료 요청 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_result.json b/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_result.json deleted file mode 100644 index 13d7d7b6c..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_underwriting_result\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"언더라이팅 인수심사 결과 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"언더라이팅 인수심사 결과 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_risk_grade.json b/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_risk_grade.json deleted file mode 100644 index 24d54cf58..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/lic_underwriting_risk_grade.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"lic_underwriting_risk_grade\",\"category\":\"LIC\",\"referenceId\":\"LIC-000001\",\"status\":\"정상\",\"summary\":\"언더라이팅 위험등급 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"언더라이팅 위험등급 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sms_cmm_claim_search.json b/dat-was-sal/src/main/resources/mock-responses/sms_cmm_claim_search.json deleted file mode 100644 index 9c4f9c037..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sms_cmm_claim_search.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "status" : "RECEIVED", - "statusLabel" : "접수", - "approvedAmount" : 150000 -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_activity_calendar.json b/dat-was-sal/src/main/resources/mock-responses/sof_activity_calendar.json deleted file mode 100644 index 8aa12eb8d..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_activity_calendar.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_activity_calendar\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"활동 일정 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"활동 일정 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_activity_daily.json b/dat-was-sal/src/main/resources/mock-responses/sof_activity_daily.json deleted file mode 100644 index e10f8dc3d..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_activity_daily.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_activity_daily\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"GA 일별 활동 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA 일별 활동 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_activity_report_status.json b/dat-was-sal/src/main/resources/mock-responses/sof_activity_report_status.json deleted file mode 100644 index 533993ac1..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_activity_report_status.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_activity_report_status\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"활동일지 제출 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"활동일지 제출 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_activity_summary.json b/dat-was-sal/src/main/resources/mock-responses/sof_activity_summary.json deleted file mode 100644 index 1f46cc369..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_activity_summary.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_activity_summary\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"GA 활동 종합 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA 활동 종합 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_call_activity.json b/dat-was-sal/src/main/resources/mock-responses/sof_call_activity.json deleted file mode 100644 index 78d5a136f..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_call_activity.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_call_activity\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"콜 활동 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"콜 활동 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_customer_consulting.json b/dat-was-sal/src/main/resources/mock-responses/sof_customer_consulting.json deleted file mode 100644 index 2fa0e9a55..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_customer_consulting.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_customer_consulting\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"고객 상담 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"고객 상담 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_field_support_request.json b/dat-was-sal/src/main/resources/mock-responses/sof_field_support_request.json deleted file mode 100644 index 3bec29c52..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_field_support_request.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_field_support_request\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"현장 지원 요청 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"현장 지원 요청 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_prospect_list.json b/dat-was-sal/src/main/resources/mock-responses/sof_prospect_list.json deleted file mode 100644 index 205d8dc9a..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_prospect_list.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_prospect_list\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"신규 발굴 고객 목록 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"신규 발굴 고객 목록 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_training_completion.json b/dat-was-sal/src/main/resources/mock-responses/sof_training_completion.json deleted file mode 100644 index f2cabec6a..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_training_completion.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_training_completion\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"교육 이수 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"교육 이수 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sof_visit_count.json b/dat-was-sal/src/main/resources/mock-responses/sof_visit_count.json deleted file mode 100644 index f43017c74..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sof_visit_count.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sof_visit_count\",\"category\":\"SOF\",\"referenceId\":\"SOF-000001\",\"status\":\"정상\",\"summary\":\"고객 방문 건수 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"고객 방문 건수 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_incentive_summary.json b/dat-was-sal/src/main/resources/mock-responses/sog_incentive_summary.json deleted file mode 100644 index 2ab905bbf..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_incentive_summary.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_incentive_summary\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"영업 인센티브 요약 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"영업 인센티브 요약 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_monthly_performance.json b/dat-was-sal/src/main/resources/mock-responses/sog_monthly_performance.json deleted file mode 100644 index 79fdc1b78..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_monthly_performance.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_monthly_performance\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"GA 월별 실적 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA 월별 실적 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_new_contract_count.json b/dat-was-sal/src/main/resources/mock-responses/sog_new_contract_count.json deleted file mode 100644 index 3d8bd3945..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_new_contract_count.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_new_contract_count\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"신계약 건수 실적 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"신계약 건수 실적 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_performance_comparison.json b/dat-was-sal/src/main/resources/mock-responses/sog_performance_comparison.json deleted file mode 100644 index 0fa8fd9bb..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_performance_comparison.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_performance_comparison\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"전년 동기 대비 실적 비교 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"전년 동기 대비 실적 비교 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_premium_performance.json b/dat-was-sal/src/main/resources/mock-responses/sog_premium_performance.json deleted file mode 100644 index 2b3e876e3..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_premium_performance.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_premium_performance\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"보험료 실적 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"보험료 실적 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_product_performance.json b/dat-was-sal/src/main/resources/mock-responses/sog_product_performance.json deleted file mode 100644 index 1d1ba6cbf..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_product_performance.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_product_performance\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"상품별 실적 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"상품별 실적 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_sales_ranking.json b/dat-was-sal/src/main/resources/mock-responses/sog_sales_ranking.json deleted file mode 100644 index c02ed4a18..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_sales_ranking.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_sales_ranking\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"GA 영업 순위 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA 영업 순위 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_target_history.json b/dat-was-sal/src/main/resources/mock-responses/sog_target_history.json deleted file mode 100644 index 6e1aab445..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_target_history.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_target_history\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"영업목표 변경 이력 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"영업목표 변경 이력 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_target_progress.json b/dat-was-sal/src/main/resources/mock-responses/sog_target_progress.json deleted file mode 100644 index ee5adc78a..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_target_progress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_target_progress\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"영업목표 달성률 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"영업목표 달성률 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sog_target_summary.json b/dat-was-sal/src/main/resources/mock-responses/sog_target_summary.json deleted file mode 100644 index 70053ed32..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sog_target_summary.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sog_target_summary\",\"category\":\"SOG\",\"referenceId\":\"SOG-000001\",\"status\":\"정상\",\"summary\":\"GA 개인별 영업목표 요약 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA 개인별 영업목표 요약 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_consent_expiry.json b/dat-was-sal/src/main/resources/mock-responses/sot_consent_expiry.json deleted file mode 100644 index 9683c2002..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_consent_expiry.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_consent_expiry\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"동의 유효기간 만료 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"동의 유효기간 만료 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_consent_withdrawal.json b/dat-was-sal/src/main/resources/mock-responses/sot_consent_withdrawal.json deleted file mode 100644 index 1b83f6920..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_consent_withdrawal.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_consent_withdrawal\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"동의 철회 이력 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"동의 철회 이력 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent.json b/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent.json deleted file mode 100644 index d000e4977..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_customer_info_consent\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"고객정보 수집·이용 동의 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"고객정보 수집·이용 동의 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent_scope.json b/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent_scope.json deleted file mode 100644 index bce43d9b7..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_customer_info_consent_scope.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_customer_info_consent_scope\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"고객정보 동의 범위 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"고객정보 동의 범위 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_channel.json b/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_channel.json deleted file mode 100644 index 2120afb03..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_channel.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_marketing_consent_channel\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"채널별 마케팅 동의 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"채널별 마케팅 동의 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_history.json b/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_history.json deleted file mode 100644 index 5697fff0d..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_history.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_marketing_consent_history\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"마케팅 동의 이력 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"마케팅 동의 이력 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_status.json b/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_status.json deleted file mode 100644 index e6d4e0fb0..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_marketing_consent_status.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_marketing_consent_status\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"마케팅 수신동의 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"마케팅 수신동의 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_consent.json b/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_consent.json deleted file mode 100644 index ae8ee1bbc..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_consent.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_subscription_design_consent\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"가입설계 동의 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"가입설계 동의 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_detail.json b/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_detail.json deleted file mode 100644 index 6c2847774..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_subscription_design_detail.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_subscription_design_detail\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"가입설계 동의 상세 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"가입설계 동의 상세 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/sot_tm_call_eligibility.json b/dat-was-sal/src/main/resources/mock-responses/sot_tm_call_eligibility.json deleted file mode 100644 index 3c7d45a59..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/sot_tm_call_eligibility.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"sot_tm_call_eligibility\",\"category\":\"SOT\",\"referenceId\":\"SOT-000001\",\"status\":\"정상\",\"summary\":\"텔레마케팅 콜 가능여부 종합 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"텔레마케팅 콜 가능여부 종합 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_answer.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_answer.json deleted file mode 100644 index d861b08a4..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_answer.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_answer\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"문의 답변 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"문의 답변 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_category.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_category.json deleted file mode 100644 index c1b03bbd8..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_category.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_category\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"문의 유형별 통계 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"문의 유형별 통계 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_detail.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_detail.json deleted file mode 100644 index 7a8f3b7a2..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_detail.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_detail\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"GA현장문의 상세 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA현장문의 상세 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_escalation.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_escalation.json deleted file mode 100644 index 8b6eaebd5..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_escalation.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_escalation\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"에스컬레이션 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"에스컬레이션 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_faq.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_faq.json deleted file mode 100644 index cd43237ec..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_faq.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_faq\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"자주묻는질문 FAQ 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"자주묻는질문 FAQ 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_list.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_list.json deleted file mode 100644 index f7daea8dc..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_list.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_list\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"GA현장문의 목록 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"GA현장문의 목록 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_manager.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_manager.json deleted file mode 100644 index 5c2811280..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_manager.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_manager\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"담당자 배정 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"담당자 배정 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_satisfaction.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_satisfaction.json deleted file mode 100644 index 2c03b22e1..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_satisfaction.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_satisfaction\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"문의 만족도 조사 결과 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"문의 만족도 조사 결과 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_sla.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_sla.json deleted file mode 100644 index 5fe9a343f..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_sla.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_sla\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"처리기한 SLA 현황 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"처리기한 SLA 현황 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_status.json b/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_status.json deleted file mode 100644 index b89d0d9a2..000000000 --- a/dat-was-sal/src/main/resources/mock-responses/spr_field_inquiry_status.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "resultCode": "SUCCESS", - "data": "{\"toolName\":\"spr_field_inquiry_status\",\"category\":\"SPR\",\"referenceId\":\"SPR-000001\",\"status\":\"정상\",\"summary\":\"문의 처리상태 조회 결과\",\"asOfDate\":\"2026-08-14\",\"details\":[\"문의 처리상태 조회 모의 상세정보\",\"외부 시스템을 변경하지 않는 조회 결과\"]}" -} diff --git a/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json b/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json deleted file mode 100644 index e6f63087e..000000000 --- a/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "properties": { - "TODO_FIELD": { - "type": "string", - "description": "TODO: 파라미터 설명을 입력하세요." - } - }, - "required": [] -} diff --git a/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json b/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json deleted file mode 100644 index 9c280db87..000000000 --- a/dat-was-sal/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "properties": { - "status": { - "type": "string", - "description": "처리 결과 상태 (SUCCESS / FAILURE)", - "enum": ["SUCCESS", "FAILURE"] - }, - "message": { - "type": "string", - "description": "처리 결과 메시지" - } - }, - "required": ["status"] -} diff --git a/dat-was-sal/src/main/resources/tool-service-manifest.yml b/dat-was-sal/src/main/resources/tool-service-manifest.yml index d37a7ff13..4002085ab 100644 --- a/dat-was-sal/src/main/resources/tool-service-manifest.yml +++ b/dat-was-sal/src/main/resources/tool-service-manifest.yml @@ -1,16 +1,22 @@ +--- mcp: manifest: routing-functions: - - name: route_to_dat-was-sal - description-serialization: 영업 업무 서버로 요청을 라우팅합니다. 영업 조직과 설계사 업무를 처리합니다. 요청의 주요 엔티티와 업무 영역을 기준으로 영업 서버를 선택합니다. - server-id: dat-was-sal - category-key: sal - product-boundary: insurance - business-domain: 영업 관리 - business-outcome: 영업 조직과 설계사 업무를 처리합니다. - primary-entities: [설계사, 영업조직, 실적] - capabilities: [설계사 조회, 영업조직 조회, 실적 조회] - select-if: 설계사, 영업조직 또는 영업실적 관련 요청인 경우 - reject-if: 고객, 계약, 상품, 시스템 운영 업무가 주된 요청인 경우 - confusable-servers: [dat-was-cus, dat-was-pro, dat-was-sys] - decision-policy: 요청의 주요 엔티티와 업무 영역을 기준으로 영업 서버를 선택합니다. + - name: "route_to_dat-was-sal" + server-id: "dat-was-sal" + category-key: "sal" + product-boundary: "영업 업무 서버를 위한 제품 범위 정의입니다." + business-domain: "영업 조직 및 설계사 관리 도메인입니다." + business-outcome: "영업 요청의 효율적인 처리와 설계사 업무 지원을 보장합니다." + primary-entities: "영업 조직, 설계사, 고객" + capabilities: "요청 라우팅, 업무 할당, 상태 조회" + select-if: "요청의 주요 엔티티가 영업 조직 또는 설계사일 경우 선택합니다." + reject-if: "요청이 다른 도메인에 속하거나 유효하지 않은 엔티티를 포함할 경우 거부합니다." + confusable-servers: + - "dat-was-cus" + - "dat-was-ehr" + - "dat-was-pro" + - "dat-was-sys" + decision-policy: "가장 가까운 영업 서버를 선택하고, 부하를 고려하여 결정합니다." + description_serialization: "이 도구는 영업 요청을 처리하며, 영업 조직과 설계사 업무를 효율적으로 라우팅하고, 부\ + 하를 고려한 결정 정책을 적용하여 적절한 서버로 분배합니다." diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCaseTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCaseTest.java deleted file mode 100644 index d588a5943..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/ClaimSearchUseCaseTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchResponse; -import org.junit.jupiter.api.Test; - -class ClaimSearchUseCaseTest { - - @Test - void createsToolRequestAndResponseDtos() { - assertNotNull(new ClaimSearchRequest()); - assertNotNull(new ClaimSearchResponse()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCaseTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCaseTest.java deleted file mode 100644 index 68164eeac..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/MemoListRetrieverUseCaseTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.MemoListRetrieverResponse; -import org.junit.jupiter.api.Test; - -class MemoListRetrieverUseCaseTest { - - @Test - void createsToolRequestAndResponseDtos() { - assertNotNull(new MemoListRetrieverRequest()); - assertNotNull(new MemoListRetrieverResponse()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImplTest.java deleted file mode 100644 index cdccd7d6b..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/cmm/usecase/impl/ClaimSearchUseCaseImplTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.cmm.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.shinhanlife.dat.mcc.biz.cmm.converter.ClaimSearchConverter; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchRequest; -import io.shinhanlife.dat.mcc.biz.cmm.dto.ClaimSearchResponse; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.MciNclaClient; -import io.shinhanlife.dat.mcc.infra.itrf.mci.ncla.io.CLCNNB00001_O; -import io.shinhanlife.glow.BizException; -import org.junit.jupiter.api.Test; - -class ClaimSearchUseCaseImplTest { - - @Test - void returnsErrorResponseWhenMciReportsABusinessCommunicationFailure() { - MciNclaClient mci = mock(MciNclaClient.class); - when(mci.callTo(eq("CLCNNB00001"), any(), any(), eq(CLCNNB00001_O.class))) - .thenThrow(bizException()); - ClaimSearchUseCaseImpl useCase = new ClaimSearchUseCaseImpl(mci, mock(ClaimSearchConverter.class)); - - ClaimSearchResponse response = useCase.searchClaim(mock(ClaimSearchRequest.class)); - - assertEquals("ERROR", response.getResultCode()); - } - - @Test - void doesNotHideUnexpectedRuntimeFailures() { - MciNclaClient mci = mock(MciNclaClient.class); - when(mci.callTo(eq("CLCNNB00001"), any(), any(), eq(CLCNNB00001_O.class))) - .thenThrow(new IllegalStateException("unexpected defect")); - ClaimSearchUseCaseImpl useCase = new ClaimSearchUseCaseImpl(mci, mock(ClaimSearchConverter.class)); - - assertThrows(IllegalStateException.class, - () -> useCase.searchClaim(mock(ClaimSearchRequest.class))); - } - - private BizException bizException() { - return new BizException("CST00477", new String[]{"MCI communication failure"}, - new RuntimeException("connection closed")); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImplTest.java deleted file mode 100644 index b11e28076..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/lic/usecase/impl/LicUnderwritingUseCaseImplTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.lic.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import io.shinhanlife.dat.mcc.biz.lic.dto.LicToolRequest; -import org.junit.jupiter.api.Test; - -class LicUnderwritingUseCaseImplTest { - - @Test - void returnsProductInfoForRequestedProductCode() { - LicToolRequest request = new LicToolRequest(); - request.setProductCode("LIC-PRD-000123"); - request.setQueryDate("2026-08-14"); - - var response = new LicUnderwritingUseCaseImpl().getProductInfo(request); - - assertEquals("lic_product_info", response.getToolName()); - assertEquals("LIC-PRD-000123", response.getReferenceId()); - assertEquals("정상", response.getStatus()); - assertFalse(response.getDetails().isEmpty()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImplTest.java deleted file mode 100644 index 8d3b531c1..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sof/usecase/impl/SofFieldActivityUseCaseImplTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sof.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import io.shinhanlife.dat.mcc.biz.sof.dto.SofToolRequest; -import org.junit.jupiter.api.Test; - -class SofFieldActivityUseCaseImplTest { - - @Test - void returnsActivityDailyForRequestedAgentId() { - SofToolRequest request = new SofToolRequest(); - request.setAgentId("SOF-AGT-000123"); - request.setQueryDate("2026-08-14"); - - var response = new SofFieldActivityUseCaseImpl().getActivityDaily(request); - - assertEquals("sof_activity_daily", response.getToolName()); - assertEquals("SOF-AGT-000123", response.getReferenceId()); - assertEquals("정상", response.getStatus()); - assertFalse(response.getDetails().isEmpty()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImplTest.java deleted file mode 100644 index 5026656bf..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sog/usecase/impl/SogSalesPerformanceUseCaseImplTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sog.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import io.shinhanlife.dat.mcc.biz.sog.dto.SogToolRequest; -import org.junit.jupiter.api.Test; - -class SogSalesPerformanceUseCaseImplTest { - - @Test - void returnsTargetSummaryForRequestedAgentId() { - SogToolRequest request = new SogToolRequest(); - request.setAgentId("SOG-AGT-000123"); - request.setQueryDate("2026-08-14"); - - var response = new SogSalesPerformanceUseCaseImpl().getTargetSummary(request); - - assertEquals("sog_target_summary", response.getToolName()); - assertEquals("SOG-AGT-000123", response.getReferenceId()); - assertEquals("정상", response.getStatus()); - assertFalse(response.getDetails().isEmpty()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImplTest.java deleted file mode 100644 index c3ad2f259..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/sot/usecase/impl/SotConsentUseCaseImplTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.sot.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import io.shinhanlife.dat.mcc.biz.sot.dto.SotToolRequest; -import org.junit.jupiter.api.Test; - -class SotConsentUseCaseImplTest { - - @Test - void returnsMarketingConsentStatusForRequestedCustomerId() { - SotToolRequest request = new SotToolRequest(); - request.setCustomerId("SOT-CUS-000123"); - request.setQueryDate("2026-08-14"); - - var response = new SotConsentUseCaseImpl().getMarketingConsentStatus(request); - - assertEquals("sot_marketing_consent_status", response.getToolName()); - assertEquals("SOT-CUS-000123", response.getReferenceId()); - assertEquals("정상", response.getStatus()); - assertFalse(response.getDetails().isEmpty()); - } -} diff --git a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImplTest.java b/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImplTest.java deleted file mode 100644 index 9a1a29835..000000000 --- a/dat-was-sal/src/test/java/io/shinhanlife/dat/mcc/biz/spr/usecase/impl/SprFieldInquiryUseCaseImplTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.shinhanlife.dat.mcc.biz.spr.usecase.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import io.shinhanlife.dat.mcc.biz.spr.dto.SprToolRequest; -import org.junit.jupiter.api.Test; - -class SprFieldInquiryUseCaseImplTest { - - @Test - void returnsFieldInquiryListForRequestedInquiryId() { - SprToolRequest request = new SprToolRequest(); - request.setInquiryId("SPR-INQ-000123"); - request.setQueryDate("2026-08-14"); - - var response = new SprFieldInquiryUseCaseImpl().getFieldInquiryList(request); - - assertEquals("spr_field_inquiry_list", response.getToolName()); - assertEquals("SPR-INQ-000123", response.getReferenceId()); - assertEquals("정상", response.getStatus()); - assertFalse(response.getDetails().isEmpty()); - } -} From ae8ab85016b766579938cbcdd7e5152d805b8ada Mon Sep 17 00:00:00 2001 From: jade Date: Thu, 17 Sep 2026 08:53:30 +0900 Subject: [PATCH 2/3] feat: add CommonCodeResolver, codes.csv and RecruitmentFeeDisclosureData companyCode mapping --- .../dat/lib/util/CommonCodeResolver.java | 180 ++ .../dat/lib/util/ToolScaffolder.java | 1858 ++++++++++++++--- dat-was-lib/src/main/resources/codes.csv | 17 + .../dat/lib/util/CommonCodeResolverTest.java | 62 + ...RecruitmentFeeDisclosureDataConverter.java | 24 +- .../RecruitmentFeeDisclosureDataRequest.java | 17 +- ...uitmentFeeDisclosureDataConverterTest.java | 67 + 7 files changed, 1941 insertions(+), 284 deletions(-) create mode 100644 dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/CommonCodeResolver.java create mode 100644 dat-was-lib/src/main/resources/codes.csv create mode 100644 dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/CommonCodeResolverTest.java create mode 100644 dat-was-pro/src/test/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverterTest.java diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/CommonCodeResolver.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/CommonCodeResolver.java new file mode 100644 index 000000000..ea4c2a88f --- /dev/null +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/CommonCodeResolver.java @@ -0,0 +1,180 @@ +package io.shinhanlife.dat.lib.util; + +import jakarta.annotation.PostConstruct; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @package io.shinhanlife.dat.lib.util + * @className CommonCodeResolver + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ +@Slf4j +@Component +public class CommonCodeResolver { + + private static final String DEFAULT_RESOURCE_PATH = "codes.csv"; + + // Group -> (Code -> Name) + private static final Map> CODE_TO_NAME_MAP = new ConcurrentHashMap<>(); + // Group -> (Normalized Name or Code -> Code) + private static final Map> NAME_TO_CODE_MAP = new ConcurrentHashMap<>(); + + static { + loadCodes(DEFAULT_RESOURCE_PATH); + } + + @PostConstruct + public void init() { + loadCodes(DEFAULT_RESOURCE_PATH); + } + + public static synchronized void reload() { + loadCodes(DEFAULT_RESOURCE_PATH); + } + + public static synchronized void loadCodes(String resourcePath) { + ClassLoader classLoader = CommonCodeResolver.class.getClassLoader(); + try (InputStream is = classLoader.getResourceAsStream(resourcePath)) { + if (is == null) { + log.warn("[CommonCodeResolver] 리소스 파일을 찾을 수 없습니다: {}", resourcePath); + return; + } + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + CODE_TO_NAME_MAP.clear(); + NAME_TO_CODE_MAP.clear(); + + String line; + boolean firstLine = true; + while ((line = reader.readLine()) != null) { + if (firstLine) { + firstLine = false; + if (line.startsWith("\uFEFF")) { + line = line.substring(1); + } + if (line.contains("그룹") || line.contains("group")) { + continue; + } + } + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + String[] parts = line.split(",", -1); + if (parts.length < 3) { + continue; + } + String group = parts[0].trim().toUpperCase(Locale.ROOT); + String code = parts[1].trim(); + String name = parts[2].trim(); + + if (group.isEmpty() || code.isEmpty()) { + continue; + } + + Map codeToName = CODE_TO_NAME_MAP.computeIfAbsent(group, k -> new ConcurrentHashMap<>()); + Map nameToCode = NAME_TO_CODE_MAP.computeIfAbsent(group, k -> new ConcurrentHashMap<>()); + + codeToName.put(code, name); + nameToCode.put(code, code); + nameToCode.put(name, code); + nameToCode.put(name.toLowerCase(Locale.ROOT), code); + nameToCode.put(name.replace(" ", ""), code); + } + log.info("[CommonCodeResolver] 공통코드 로드 완료: {}개 그룹", CODE_TO_NAME_MAP.size()); + } + } catch (Exception e) { + log.error("[CommonCodeResolver] 공통코드 로드 중 오류 발생: {}", e.getMessage(), e); + } + } + + /** + * 입력값(명칭 또는 코드)을 처리계 표준 코드값으로 변환합니다. + * + * @param group 코드 그룹명 (예: COMPANY, STATUS) + * @param input 사용자가 입력한 명칭("삼성전자") 또는 코드("005930") + * @return 매핑된 코드값(예: "005930"). 매핑되지 않으면 원본 입력값 반환. + */ + public static String resolve(String group, String input) { + return resolve(group, input, input); + } + + /** + * 입력값(명칭 또는 코드)을 처리계 표준 코드값으로 변환합니다. + * + * @param group 코드 그룹명 + * @param input 입력값 + * @param defaultValue 매핑 실패 시 반환할 기본값 + * @return 매핑된 코드값 또는 defaultValue + */ + public static String resolve(String group, String input, String defaultValue) { + if (input == null || input.isBlank()) { + return defaultValue; + } + if (group == null) { + return input.trim(); + } + String normalizedGroup = group.trim().toUpperCase(Locale.ROOT); + Map nameToCode = NAME_TO_CODE_MAP.get(normalizedGroup); + if (nameToCode == null) { + return defaultValue; + } + String trimmed = input.trim(); + String matched = nameToCode.get(trimmed); + if (matched != null) { + return matched; + } + matched = nameToCode.get(trimmed.toLowerCase(Locale.ROOT)); + if (matched != null) { + return matched; + } + matched = nameToCode.get(trimmed.replace(" ", "")); + if (matched != null) { + return matched; + } + return defaultValue; + } + + /** + * 코드값에 해당하는 표준 명칭을 반환합니다. (응답 변환 시 사용) + */ + public static String getName(String group, String code) { + if (group == null || code == null) { + return code; + } + String normalizedGroup = group.trim().toUpperCase(Locale.ROOT); + Map codeToName = CODE_TO_NAME_MAP.get(normalizedGroup); + if (codeToName != null) { + return codeToName.getOrDefault(code.trim(), code); + } + return code; + } + + /** + * 특정 그룹의 전체 코드-명칭 맵을 반환합니다. + */ + public static Map getCodeMap(String group) { + if (group == null) { + return Collections.emptyMap(); + } + Map map = CODE_TO_NAME_MAP.get(group.trim().toUpperCase(Locale.ROOT)); + return map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap(); + } +} \ No newline at end of file diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java index 94ad3ee57..680acaafc 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java @@ -8,6 +8,7 @@ import java.nio.file.Paths; import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -46,6 +47,23 @@ public class ToolScaffolder { private static final String BASE_PACKAGE = "io.shinhanlife.dat.mcc"; private static final String BASE_PACKAGE_PATH = "src/main/java/io/shinhanlife/dat/mcc"; + public enum PagingMode { + NONE, + SCROLL, + PAGE_NUMBER; + + static PagingMode from(String value) { + if (value == null || value.isBlank()) { + return NONE; + } + try { + return PagingMode.valueOf(value.trim().toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException ignored) { + return NONE; + } + } + } + public record FieldDefinition(String name, String type, String description, List examples, String pattern, boolean required, List enumValues, String itemType, List itemFields) { public FieldDefinition(String name, String type, String description, List examples, String pattern, boolean required) { @@ -68,7 +86,48 @@ public class ToolScaffolder { String displayDescription, List exampleQueries, List tags, - String ownerOrg) { + String ownerOrg, + Long timeoutMillis, + Integer retryMaxAttempts, + String pagingMode) { + + public ToolDefinitionOptions(String functionDescription, String whenToUse, String whenNotToUse, + String ioLimits, String displayDescription, List exampleQueries, + List tags, String ownerOrg, Long timeoutMillis, + Integer retryMaxAttempts) { + this(functionDescription, whenToUse, whenNotToUse, ioLimits, displayDescription, exampleQueries, tags, + ownerOrg, timeoutMillis, retryMaxAttempts, null); + } + + public ToolDefinitionOptions(String functionDescription, String whenToUse, String whenNotToUse, + String ioLimits, String displayDescription, List exampleQueries, + List tags, String ownerOrg) { + this(functionDescription, whenToUse, whenNotToUse, ioLimits, displayDescription, exampleQueries, tags, + ownerOrg, null, null, null); + } + + public long timeoutMillisOrDefault() { + return timeoutMillis != null && timeoutMillis > 0 ? timeoutMillis : 5000L; + } + + public int retryMaxAttemptsOrDefault() { + return retryMaxAttempts != null && retryMaxAttempts > 0 ? retryMaxAttempts : 3; + } + + public PagingMode pagingModeOrNone() { + return PagingMode.from(pagingMode); + } + } + + public static String businessProposalGuide() { + return """ + [업무 제안서 작성 가이드] + 통합계약원부 조회 + 1. 조회 대상·식별 기준: 무엇을 어떤 값으로 찾는지 + 계약번호가 있으면 상세 원부를 조회 + 2. 조회 목적·사용처: 어떤 업무 상황에서 쓰는지 + 해지·대출·보험금 상세는 별도 Tool + """; } public static String scaffoldUseCase(String useCaseName, String moduleName, String author, @@ -76,7 +135,11 @@ public class ToolScaffolder { if (tools == null || tools.isEmpty()) { throw new IllegalArgumentException("At least one Tool method is required."); } + boolean hasMci = tools.stream().anyMatch(t -> "MCI".equalsIgnoreCase(t.routingType())); String useCaseBaseName = toPascalCase(useCaseName); + if (hasMci) { + useCaseBaseName = abbreviatedMciSourceBaseName(useCaseBaseName); + } String group = tools.getFirst().group().toLowerCase(Locale.ROOT); validateToolMethods(tools, group); @@ -93,13 +156,11 @@ public class ToolScaffolder { Path dtoDir = sourceRoot.resolve(Paths.get("biz", group, "dto")); Path converterDir = sourceRoot.resolve(Paths.get("biz", group, "converter")); Path definitionDir = moduleRoot.resolve(Paths.get("src", "main", "resources", "tool-definitions", group)); - Path mockDir = moduleRoot.resolve(Paths.get("src", "main", "resources", "mock-responses")); Files.createDirectories(useCaseDir); Files.createDirectories(implDir); Files.createDirectories(dtoDir); Files.createDirectories(converterDir); Files.createDirectories(definitionDir); - Files.createDirectories(mockDir); String bizPackage = BASE_PACKAGE + ".biz." + group; Path useCaseFile = useCaseDir.resolve(useCaseBaseName + "UseCase.java"); @@ -112,7 +173,9 @@ public class ToolScaffolder { } else { writeUtf8(useCaseFile, groupedUseCaseContent(bizPackage, useCaseBaseName, moduleName, tools)); writeUtf8(useCaseImplFile, groupedUseCaseImplContent(bizPackage, useCaseBaseName, tools)); - writeUtf8(converterFile, groupedConverterContent(bizPackage, useCaseBaseName, tools)); + if (!hasMci) { + writeUtf8(converterFile, groupedConverterContent(bizPackage, useCaseBaseName, tools)); + } } StringBuilder log = new StringBuilder("\n=========================================\n") @@ -122,13 +185,16 @@ public class ToolScaffolder { .append("[Usecase Interface] ").append(useCaseFile).append("\n") .append("[Usecase Impl] ").append(useCaseImplFile).append("\n"); for (ToolMethodDefinition tool : tools) { - writeGroupedToolFiles(moduleRoot, sourceRoot, dtoDir, definitionDir, mockDir, bizPackage, tool, moduleName, log); + writeGroupedToolFiles(moduleRoot, sourceRoot, dtoDir, definitionDir, bizPackage, tool, moduleName, log); if ("HTTP".equalsIgnoreCase(tool.routingType())) { - ensureLocalHttpApiConfiguration(moduleRoot, tool.httpApiName(), + Path glowConfig = ensureLocalHttpApiConfiguration(moduleRoot, tool.httpApiName(), toToolName(moduleName, tool.group(), toPascalCase(tool.baseName()))); + log.append("[HTTP Config] ").append(glowConfig).append("\n"); } } - log.append("[Converter] ").append(converterFile).append("\n"); + if (!hasMci) { + log.append("[Converter] ").append(converterFile).append("\n"); + } return log.toString(); } @@ -162,41 +228,119 @@ public class ToolScaffolder { } } + private static String formatClientSystemCode(String code, String delimiter) { + if (code == null) return ""; + if (code.length() == 9) { + return code.substring(1, 4).toLowerCase(Locale.ROOT) + delimiter + code.substring(4, 5).toLowerCase(Locale.ROOT); + } else if (code.length() == 4) { + return code.substring(0, 3).toLowerCase(Locale.ROOT) + delimiter + code.substring(3).toLowerCase(Locale.ROOT); + } + return code.toLowerCase(Locale.ROOT); + } + + private static String mciClientPrefix(String clientSystemCode) { + String normalized = clientSystemCode == null ? "" : clientSystemCode.trim().toLowerCase(Locale.ROOT); + return normalized.length() == 9 ? normalized.substring(1, 5) : normalized; + } + + private static String mciClientClassName(String clientSystemCode) { + return "Mci" + toPascalCase(mciClientPrefix(clientSystemCode)) + "Client"; + } + + private static String mciClientVariable(String clientSystemCode) { + String prefix = toPascalCase(mciClientPrefix(clientSystemCode)); + return "mci" + prefix + "Client"; + } + private static void writeGroupedToolFiles(Path moduleRoot, Path sourceRoot, Path dtoDir, Path definitionDir, - Path mockDir, String bizPackage, ToolMethodDefinition tool, + String bizPackage, ToolMethodDefinition tool, String moduleName, StringBuilder log) throws IOException { - String baseName = toPascalCase(tool.baseName()); boolean mci = "MCI".equalsIgnoreCase(tool.routingType()); - String code = mci ? (tool.clientSystemCode().length() == 4 ? tool.clientSystemCode().substring(0,3).toLowerCase(Locale.ROOT) + "/" + tool.clientSystemCode().substring(3).toLowerCase(Locale.ROOT) : tool.clientSystemCode().toLowerCase(Locale.ROOT)) : toPackageSegment(tool.httpApiName()); + String toolBaseName = toPascalCase(tool.baseName()); + String baseName = mci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; + String code = mci ? formatClientSystemCode(tool.clientSystemCode(), "/") : toPackageSegment(tool.httpApiName()); String ioPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." : ".infra.itrf.http.") + code.replace("/", "."); Path clientDir = sourceRoot.resolve(Paths.get("infra", "itrf", mci ? "mci" : "http", code)); Path ioDir = clientDir.resolve("io"); Files.createDirectories(ioDir); + ToolDefinitionOptions options = tool.definitionOptions() == null + ? new ToolDefinitionOptions(null, null, null, null, null, List.of(), List.of(), null) + : tool.definitionOptions(); + PagingMode pagingMode = mci ? options.pagingModeOrNone() : PagingMode.NONE; + String ioPrefix = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) ? tool.clientSystemCode().toUpperCase() : tool.interfaceId(); + if (pagingMode != PagingMode.NONE) { + String group = bizPackage.substring(bizPackage.lastIndexOf('.') + 1); + Path pagingDir = moduleRoot.resolve(Paths.get(BASE_PACKAGE_PATH, "biz", group, "paging")); + String clientCls = (tool.clientSystemCode() != null && (tool.clientSystemCode().length() == 4 || tool.clientSystemCode().length() == 9)) + ? mciClientClassName(tool.clientSystemCode()) + : "AxhubMciComponent"; + String targetPkg = mciTargetSystemPackage(tool.clientSystemCode()); + String convPkg = bizPackage + ".converter" + (targetPkg != null ? "." + targetPkg : ""); + String convName = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) + ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" + : baseName + "Converter"; + String recSvcId = tool.clientSystemCode() != null ? tool.clientSystemCode().toUpperCase() : ""; + writePagingComponents(pagingDir, bizPackage, baseName, pagingMode, ioPackage, ioPrefix, clientCls, convPkg, convName, tool.interfaceId(), recSvcId); + log.append("Generated ").append(pagingMode).append(" paging components for ").append(baseName).append(".\n"); + } writeUtf8(dtoDir.resolve(baseName + "Request.java"), - dtoContent(bizPackage + ".dto", baseName + "Request", tool.inputFields(), "", "", true)); + dtoContent(bizPackage + ".dto", baseName + "Request", tool.inputFields(), "", "", true, pagingMode)); writeUtf8(dtoDir.resolve(baseName + "Response.java"), - dtoContent(bizPackage + ".dto", baseName + "Response", tool.outputFields(), "", "", false)); + dtoContent(bizPackage + ".dto", baseName + "Response", tool.outputFields(), "", "", false, pagingMode)); writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Request", tool.inputFields()); writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Response", tool.outputFields()); if (mci) { - writeUtf8(ioDir.resolve(tool.interfaceId() + "_I.java"), - mciIoContent("infra.itrf.mci." + code.replace("/", "."), tool.interfaceId() + "_I", tool.inputFields(), "", "")); - writeUtf8(ioDir.resolve(tool.interfaceId() + "_O.java"), - mciIoContent("infra.itrf.mci." + code.replace("/", "."), tool.interfaceId() + "_O", tool.outputFields(), "", "")); - writeStructuredFieldTypes(ioDir, ioPackage + ".io", tool.interfaceId() + "_I", tool.inputFields()); - writeStructuredFieldTypes(ioDir, ioPackage + ".io", tool.interfaceId() + "_O", tool.outputFields()); + writeUtf8(ioDir.resolve(ioPrefix + "_I.java"), + mciIoContent("infra.itrf.mci." + code.replace("/", "."), ioPrefix + "_I", tool.inputFields(), "", "", pagingMode)); + writeUtf8(ioDir.resolve(ioPrefix + "_O.java"), + mciIoContent("infra.itrf.mci." + code.replace("/", "."), ioPrefix + "_O", tool.outputFields(), "", "", pagingMode)); + writeStructuredFieldTypes(ioDir, ioPackage + ".io", ioPrefix + "_I", tool.inputFields()); + writeStructuredFieldTypes(ioDir, ioPackage + ".io", ioPrefix + "_O", tool.outputFields()); String sysCode = tool.clientSystemCode(); - if (sysCode != null && sysCode.length() == 4) { - String normalizedSysCode = sysCode.toLowerCase(Locale.ROOT); - String clientCap = normalizedSysCode.substring(0, 1).toUpperCase(Locale.ROOT) - + normalizedSysCode.substring(1); + if (sysCode != null && (sysCode.length() == 4 || sysCode.length() == 9)) { + String clientCap = toPascalCase(mciClientPrefix(sysCode)); + String recSvcId = sysCode.toUpperCase(); + String itrfId = tool.interfaceId(); writeUtf8(clientDir.resolve("Mci" + clientCap + "Client.java"), - "package " + ioPackage + ";\n\nimport io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;\nimport io.shinhanlife.glow.communication.dto.Transfer;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Component;\n\n@Component\n@RequiredArgsConstructor\npublic class Mci" + clientCap + "Client {\n private final AxhubMciComponent mci;\n\n public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) throws Exception {\n return mci.callTo(interfaceId, dummy, mciReq, resType);\n }\n}\n"); + "package " + ioPackage + ";\n\n" + + "import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;\n" + + "import io.shinhanlife.glow.communication.dto.Transfer;\n" + + "import " + ioPackage + ".io." + ioPrefix + "_I;\n" + + "import " + ioPackage + ".io." + ioPrefix + "_O;\n" + + "import lombok.RequiredArgsConstructor;\n" + + "import org.springframework.stereotype.Component;\n\n" + + "@Component\n" + + "@RequiredArgsConstructor\n" + + "public class Mci" + clientCap + "Client {\n\n" + + " private static final String INTERFACE_ID = \"" + itrfId + "\";\n" + + " private static final String RECEIVE_SERVICE_ID = \"" + recSvcId + "\";\n\n" + + " private final AxhubMciComponent mciComponent;\n\n" + + " public Transfer callTo(String interfaceId, String receiveServiceId, Object mciReq, Class resType) {\n" + + " return mciComponent.callTo(interfaceId, receiveServiceId, mciReq, resType);\n" + + " }\n\n" + + " public " + ioPrefix + "_O call" + toPascalCase(ioPrefix) + "(" + ioPrefix + "_I request) {\n" + + " Transfer<" + ioPrefix + "_O> transfer = mciComponent.callTo(\n" + + " INTERFACE_ID, RECEIVE_SERVICE_ID, request, " + ioPrefix + "_O.class);\n" + + " return transfer == null ? null : transfer.getBody();\n" + + " }\n" + + "}\n"); } else { writeUtf8(clientDir.resolve(baseName + "Client.java"), groupedMciClientContent(ioPackage, baseName, tool.interfaceId())); } - writeUtf8(sourceRoot.resolve(Paths.get("biz", tool.group().toLowerCase(Locale.ROOT), "converter", baseName + "Converter.java")), - groupedMciConverterContent(bizPackage, baseName, ioPackage, tool.interfaceId())); + String targetPkg = mciTargetSystemPackage(tool.clientSystemCode()); + String converterPkg = bizPackage + ".converter" + (targetPkg != null ? "." + targetPkg : ""); + Path targetConverterDir = sourceRoot.resolve(Paths.get("biz", tool.group().toLowerCase(Locale.ROOT), "converter")); + if (targetPkg != null) { + for (String seg : targetPkg.split("\\.")) { + targetConverterDir = targetConverterDir.resolve(seg); + } + } + Files.createDirectories(targetConverterDir); + String converterName = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) + ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" + : baseName + "Converter"; + writeUtf8(targetConverterDir.resolve(converterName + ".java"), + groupedMciConverterContent(converterPkg, bizPackage, baseName, ioPackage, ioPrefix, converterName)); } else { writeUtf8(ioDir.resolve(baseName + "HttpRequest.java"), dtoContent(ioPackage + ".io", baseName + "HttpRequest", tool.inputFields(), "", "", true)); @@ -210,8 +354,7 @@ public class ToolScaffolder { groupedHttpConverterContent(bizPackage, baseName, ioPackage)); } - String toolName = toToolName(moduleName, tool.group(), baseName); - writeUtf8(mockDir.resolve(toolName + ".json"), mockResponseContent(tool.outputFields())); + String toolName = toToolName(moduleName, tool.group(), toolBaseName); log.append("[Tool] ").append(toolName).append(" -> ").append(clientDir.resolve(baseName + "Client.java")).append("\n"); } @@ -220,20 +363,22 @@ public class ToolScaffolder { StringBuilder imports = new StringBuilder(); StringBuilder methods = new StringBuilder(); for (ToolMethodDefinition tool : tools) { - String baseName = toPascalCase(tool.baseName()); + boolean mci = "MCI".equalsIgnoreCase(tool.routingType()); + String toolBaseName = toPascalCase(tool.baseName()); + String baseName = mci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n") .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n"); boolean isMutation = isMutationTool(baseName); ToolDefinitionOptions opts = tool.definitionOptions() == null ? new ToolDefinitionOptions(null, null, null, null, null, null, null, null) : tool.definitionOptions(); - - methods.append(" @McpTool(name = \"").append(toToolName(moduleName, tool.group(), baseName)) + + methods.append(" @McpTool(name = \"").append(toToolName(moduleName, tool.group(), toolBaseName)) .append("\", title = \"").append(javaText(option(tool.title(), baseName))) .append("\", description = \"").append(javaText(option(tool.description(), ""))).append("\")\n") .append(" @GrowToolHint(\n") .append(" requiresApproval = ").append(isMutation).append(",\n") .append(" categoryKey = \"").append(tool.group().toLowerCase(Locale.ROOT)).append("\",\n") - .append(" timeoutMillis = 5000L,\n") - .append(" retryMaxAttempts = 3,\n"); + .append(" timeoutMillis = ").append(opts.timeoutMillisOrDefault()).append("L,\n") + .append(" retryMaxAttempts = ").append(opts.retryMaxAttemptsOrDefault()).append(",\n"); if (tool.interfaceId() != null && !tool.interfaceId().isBlank()) { methods.append(" mappingId = \"").append(javaText(tool.interfaceId())).append("\",\n"); } @@ -242,7 +387,7 @@ public class ToolScaffolder { .append(" whenNotToUse = \"").append(javaText(opts.whenNotToUse() != null && !opts.whenNotToUse().isBlank() ? opts.whenNotToUse() : "정보 변경이나 실행 작업에는 사용하지 않습니다.")).append("\",\n") .append(" ioLimits = \"").append(javaText(opts.ioLimits() != null && !opts.ioLimits().isBlank() ? opts.ioLimits() : "정의된 입력 항목만 허용하며 업무 결과만 반환합니다.")).append("\",\n") .append(" displayDescription = \"").append(javaText(opts.displayDescription() != null && !opts.displayDescription().isBlank() ? opts.displayDescription() : option(tool.title(), baseName) + " 정보를 처리합니다.")).append("\",\n"); - + List examples = opts.exampleQueries(); if (examples == null || examples.isEmpty()) { examples = List.of(option(tool.title(), baseName) + " 정보를 보여줘", option(tool.title(), baseName) + " 확인해줘", "현재 " + option(tool.title(), baseName) + " 알려줘"); @@ -252,7 +397,7 @@ public class ToolScaffolder { .append("},\n") .append(" destructive = ").append(isMutation).append(",\n") .append(" idempotent = ").append(!isMutation).append(",\n"); - + List tags = opts.tags(); if (tags == null || tags.isEmpty()) { tags = List.of(tool.group().toLowerCase(Locale.ROOT), isMutation ? "처리" : "조회"); @@ -277,63 +422,322 @@ public class ToolScaffolder { StringBuilder fields = new StringBuilder(); StringBuilder methods = new StringBuilder(); for (ToolMethodDefinition tool : tools) { - String baseName = toPascalCase(tool.baseName()); - String clientClassName; - String clientVariable; boolean mci = "MCI".equalsIgnoreCase(tool.routingType()); - if (mci) { - String sysCode = tool.clientSystemCode().toLowerCase(Locale.ROOT); - clientClassName = "Mci" + sysCode.substring(0, 1).toUpperCase(Locale.ROOT) + sysCode.substring(1) + "Client"; - clientVariable = "mci" + sysCode.substring(0, 1).toUpperCase(Locale.ROOT) + sysCode.substring(1) + "Client"; + String toolBaseName = toPascalCase(tool.baseName()); + String baseName = mci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; + ToolDefinitionOptions options = tool.definitionOptions() == null + ? new ToolDefinitionOptions(null, null, null, null, null, List.of(), List.of(), null) + : tool.definitionOptions(); + PagingMode pagingMode = mci ? options.pagingModeOrNone() : PagingMode.NONE; + + if (pagingMode != PagingMode.NONE) { + String pagingSuffix = pagingMode == PagingMode.SCROLL ? "ScrollPaging" : "PageNumberPaging"; + String pagingInfoType = pagingMode == PagingMode.SCROLL ? "ScrollPagingInfo" : "PgNumPagingInfo"; + String pagingInterface = baseName + pagingSuffix; + String pagingVar = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + pagingSuffix; + + imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n") + .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n") + .append("import ").append(bizPackage).append(".paging.").append(pagingInterface).append(";\n") + .append("import io.shinhanlife.dat.lib.paging.MciPage;\n") + .append("import io.shinhanlife.dat.lib.paging.").append(pagingInfoType).append(";\n"); + + if (!fields.toString().contains(" " + pagingVar + ";")) { + fields.append(" private final ").append(pagingInterface).append(" ").append(pagingVar).append(";\n"); + } + methods.append(groupedToolPagingMethodContent(tool, baseName, pagingVar, pagingMode, pagingInfoType)); } else { - clientClassName = baseName + "Client"; - clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; + String clientClassName; + String clientVariable; + String ioPrefix = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) ? tool.clientSystemCode().toUpperCase() : tool.interfaceId(); + if (mci) { + clientClassName = mciClientClassName(tool.clientSystemCode()); + clientVariable = "mci"; + } else { + clientClassName = baseName + "Client"; + clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; + } + String targetPkg = mci ? mciTargetSystemPackage(tool.clientSystemCode()) : null; + String converterPkg = bizPackage + ".converter" + (targetPkg != null ? "." + targetPkg : ""); + String converterName = (mci && tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) + ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" + : baseName + "Converter"; + String converterVariable = "converter"; + String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + formatClientSystemCode(tool.clientSystemCode(), ".") + : ".infra.itrf.http." + toPackageSegment(tool.httpApiName())); + imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n") + .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n") + .append("import ").append(converterPkg).append(".").append(converterName).append(";\n") + .append("import ").append(integrationPackage).append(".").append(clientClassName).append(";\n") + .append("import ").append(integrationPackage).append(".io.").append(mci ? ioPrefix + "_I;\n" : baseName + "HttpRequest;\n") + .append("import ").append(integrationPackage).append(".io.").append(mci ? ioPrefix + "_O;\n" : baseName + "HttpResponse;\n"); + if (mci) { + imports.append("import io.shinhanlife.glow.communication.dto.Transfer;\n"); + } + if (!fields.toString().contains(" " + clientVariable + ";")) { + fields.append(" private final ").append(clientClassName).append(" ").append(clientVariable).append(";\n"); + } + if (!fields.toString().contains(" " + converterVariable + ";")) { + fields.append(" private final ").append(converterName).append(" ").append(converterVariable).append(";\n"); + } + methods.append(groupedToolMethodContent(tool, baseName, converterVariable, clientVariable, ioPrefix, mci)); } - String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter"; - String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + (tool.clientSystemCode().length() == 4 ? tool.clientSystemCode().substring(0,3).toLowerCase(Locale.ROOT) + "." + tool.clientSystemCode().substring(3).toLowerCase(Locale.ROOT) : tool.clientSystemCode().toLowerCase(Locale.ROOT)) - : ".infra.itrf.http." + toPackageSegment(tool.httpApiName())); - imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n") - .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n") - .append("import ").append(bizPackage).append(".converter.").append(baseName).append("Converter;\n") - .append("import ").append(integrationPackage).append(".").append(clientClassName).append(";\n") - .append("import ").append(integrationPackage).append(".io.").append(mci ? tool.interfaceId() + "_I;\n" : baseName + "HttpRequest;\n") - .append("import ").append(integrationPackage).append(".io.").append(mci ? tool.interfaceId() + "_O;\n" : baseName + "HttpResponse;\n"); - if (!fields.toString().contains(" " + clientVariable + ";")) { - fields.append(" private final ").append(clientClassName).append(" ").append(clientVariable).append(";\n"); - } - fields.append(" private final ").append(baseName).append("Converter ").append(converterVariable).append(";\n"); - methods.append(" @Override\n public ").append(baseName).append("Response ").append(tool.methodName()) - .append("(").append(baseName).append("Request req) {\n") - .append(" ").append(mci ? tool.interfaceId() + "_I" : baseName + "HttpRequest").append(" request = ").append(converterVariable).append(".toRequest(req);\n") - .append(" ").append(mci ? tool.interfaceId() + "_O" : baseName + "HttpResponse").append(" response = ").append(clientVariable) - .append(mci ? ".callTo(\"" + tool.interfaceId() + "\", null, request, " + tool.interfaceId() + "_O.class).getBody();\n" : ".call(request, " + baseName + "HttpResponse.class);\n") - .append(" ").append(baseName).append("Response toolResponse = ").append(converterVariable).append(".toResponse(response);\n") - .append(" if (toolResponse == null) toolResponse = new ").append(baseName).append("Response();\n") - .append(" toolResponse.setResultCode(\"SUCCESS\");\n") - .append(" return toolResponse;\n }\n\n"); + } + boolean hasMciOrPaging = tools.stream().anyMatch(t -> "MCI".equalsIgnoreCase(t.routingType())); + String slf4jAnno = hasMciOrPaging ? "@Slf4j\n" : ""; + if (hasMciOrPaging) { + imports.append("import lombok.extern.slf4j.Slf4j;\n"); + } + boolean hasPaging = tools.stream().anyMatch(t -> t.definitionOptions() != null && t.definitionOptions().pagingModeOrNone() != PagingMode.NONE); + if (hasPaging) { + methods.append(""" + + private void mergeResponseData(Object target, Object src) { + if (target == null || src == null) return; + for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { + if (java.util.List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + java.util.List srcList = (java.util.List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + java.util.List targetList = (java.util.List) field.get(target); + if (targetList == null) { + targetList = new java.util.ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof java.util.ArrayList)) { + targetList = new java.util.ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + } + """); } return "package " + bizPackage + ".usecase.impl;\n\n" + "import " + bizPackage + ".usecase." + useCaseBaseName + "UseCase;\n" + "import lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\n" + imports - + "\n@Service\n@RequiredArgsConstructor\npublic class " + useCaseBaseName + "UseCaseImpl implements " + useCaseBaseName + "UseCase {\n\n" + + "\n" + slf4jAnno + "@Service\n@RequiredArgsConstructor\npublic class " + useCaseBaseName + "UseCaseImpl implements " + useCaseBaseName + "UseCase {\n\n" + fields + "\n" + methods + "}\n"; } + private static String groupedToolPagingMethodContent(ToolMethodDefinition tool, String baseName, + String pagingVariable, PagingMode pagingMode, + String pagingInfoType) { + String snakeToolName = (tool.group() != null && !tool.group().isBlank() ? tool.group().toLowerCase(Locale.ROOT) + "_" : "") + + toKebabCase(baseName).toLowerCase(Locale.ROOT).replace("-", "_"); + if (pagingMode == PagingMode.PAGE_NUMBER) { + return """ + + @Override + public %sResponse %s(%sRequest req) { + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + try { + %s pagingInfo = null; + %s pagingInfoLast = null; + %sResponse finalResponse = null; + int loopCount = 0; + final int MAX_PAGING_COUNT = 10; + boolean hasMore = false; + + while (loopCount < MAX_PAGING_COUNT) { + loopCount++; + MciPage<%sResponse, %s> page = %s.fetch(req, pagingInfo); + pagingInfoLast = page.pagingInfo(); + if (finalResponse == null) { + finalResponse = page.data(); + } else if (page.data() != null) { + mergeResponseData(finalResponse, page.data()); + } + if (!page.hasNext()) { + hasMore = false; + break; + } + hasMore = true; + pagingInfo = page.pagingInfo(); + } + + if (finalResponse == null) { + finalResponse = new %sResponse(); + } + finalResponse.setResultCode("SUCCESS"); + finalResponse.setHasMore(hasMore); + if (pagingInfoLast != null) { + int lastPageNo = Math.max(1, pagingInfoLast.getPageNo() - 1); + finalResponse.setPageNo(lastPageNo); + finalResponse.setTotalPageCount(pagingInfoLast.getTotaPageCn()); + finalResponse.setTotalCount(pagingInfoLast.getTotaPageDataCc()); + } else { + finalResponse.setPageNo(1); + finalResponse.setTotalPageCount(1); + } + if (hasMore) { + finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (현재 " + finalResponse.getPageNo() + "페이지 / 총 " + finalResponse.getTotalPageCount() + "페이지, hasMore=true)."); + } else { + finalResponse.setResultMessage("MCI 페이징 조회가 완료되었습니다 (현재 " + finalResponse.getPageNo() + "페이지 / 총 " + finalResponse.getTotalPageCount() + "페이지)."); + } + return finalResponse; + } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse errorResponse = new %sResponse(); + errorResponse.setResultCode("ERROR"); + errorResponse.setResultMessage("MCI paging call failed: " + e.getMessage()); + errorResponse.setHasMore(false); + errorResponse.setPageNo(1); + errorResponse.setTotalPageCount(0); + errorResponse.setTotalCount(0); + return errorResponse; + } + } + """.formatted( + baseName, tool.methodName(), baseName, + pagingMode, snakeToolName, pagingMode, + pagingInfoType, + pagingInfoType, + baseName, + baseName, pagingInfoType, pagingVariable, + baseName, + baseName, baseName); + } else { + return """ + + @Override + public %sResponse %s(%sRequest req) { + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + try { + %s pagingInfo = null; + %sResponse finalResponse = null; + int loopCount = 0; + final int MAX_PAGING_COUNT = 10; + boolean hasMore = false; + + while (loopCount < MAX_PAGING_COUNT) { + loopCount++; + MciPage<%sResponse, %s> page = %s.fetch(req, pagingInfo); + if (finalResponse == null) { + finalResponse = page.data(); + } else if (page.data() != null) { + mergeResponseData(finalResponse, page.data()); + } + if (!page.hasNext()) { + hasMore = false; + break; + } + hasMore = true; + pagingInfo = page.pagingInfo(); + } + + if (finalResponse == null) { + finalResponse = new %sResponse(); + } + finalResponse.setResultCode("SUCCESS"); + finalResponse.setHasMore(hasMore); + if (hasMore) { + finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (총 " + loopCount + "회 호출, hasMore=true)."); + } else { + finalResponse.setResultMessage("MCI 스크롤 페이징 조회가 완료되었습니다 (총 " + loopCount + "회 호출)."); + } + return finalResponse; + } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse errorResponse = new %sResponse(); + errorResponse.setResultCode("ERROR"); + errorResponse.setResultMessage("MCI paging call failed: " + e.getMessage()); + errorResponse.setHasMore(false); + return errorResponse; + } + } + """.formatted( + baseName, tool.methodName(), baseName, + pagingMode, snakeToolName, pagingMode, + pagingInfoType, + baseName, + baseName, pagingInfoType, pagingVariable, + baseName, + baseName, baseName); + } + } + + private static String groupedToolMethodContent(ToolMethodDefinition tool, String baseName, + String converterVariable, String clientVariable, + String ioPrefix, boolean mci) { + if (mci) { + String snakeToolName = (tool.group() != null && !tool.group().isBlank() ? tool.group().toLowerCase(Locale.ROOT) + "_" : "") + + toKebabCase(baseName).toLowerCase(Locale.ROOT).replace("-", "_"); + String receiveServiceId = tool.clientSystemCode() != null ? tool.clientSystemCode().toUpperCase() : ""; + return """ + + @Override + public %sResponse %s(%sRequest req) { + log.info("[MCI Tool] {} 요청 수신.", "%s"); + try { + // MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO) + %s_I mciReq = %s.toRequest(req); + + Transfer<%s_O> resTransfer = %s.callTo( + "%s", + "%s", + mciReq, + %s_O.class + ); + %sResponse response = new %sResponse(); + if (resTransfer != null && resTransfer.getBody() != null) { + response = %s.toResponse(resTransfer.getBody()); + } + response.setResultCode("SUCCESS"); + return response; + } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse errorResponse = new %sResponse(); + errorResponse.setResultCode("ERROR"); + errorResponse.setResultMessage("MCI call failed: " + e.getMessage()); + return errorResponse; + } + } + """.formatted(baseName, tool.methodName(), baseName, snakeToolName, + ioPrefix, converterVariable, + ioPrefix, clientVariable, tool.interfaceId(), receiveServiceId, ioPrefix, + baseName, baseName, + converterVariable, + baseName, baseName); + } + return """ + + @Override + public %sResponse %s(%sRequest req) { + %sHttpRequest request = %s.toRequest(req); + %sHttpResponse response = %s.call(request, %sHttpResponse.class); + %sResponse toolResponse = %s.toResponse(response); + if (toolResponse == null) toolResponse = new %sResponse(); + toolResponse.setResultCode("SUCCESS"); + return toolResponse; + } + """.formatted(baseName, tool.methodName(), baseName, baseName, converterVariable, baseName, + clientVariable, baseName, baseName, converterVariable, baseName); + } + private static String groupedConverterContent(String bizPackage, String useCaseBaseName, List tools) { return "package " + bizPackage + ".converter;\n\n/** Per-Tool converters are generated beside this compatibility marker. */\n" + "public interface " + useCaseBaseName + "Converter {\n}\n"; } - private static String groupedMciConverterContent(String bizPackage, String baseName, String ioPackage, String interfaceId) { - return "package " + bizPackage + ".converter;\n\n" + private static String groupedMciConverterContent(String converterPackage, String bizPackage, String baseName, String ioPackage, String interfaceId, String converterName) { + return "package " + converterPackage + ";\n\n" + "import " + bizPackage + ".dto." + baseName + "Request;\n" + "import " + bizPackage + ".dto." + baseName + "Response;\n" + "import " + ioPackage + ".io." + interfaceId + "_I;\n" + "import " + ioPackage + ".io." + interfaceId + "_O;\n" + "import org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n\n" + "@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n" - + "public interface " + baseName + "Converter {\n" + + "public interface " + converterName + " {\n" + " " + interfaceId + "_I toRequest(" + baseName + "Request request);\n" + " " + baseName + "Response toResponse(" + interfaceId + "_O response);\n}\n"; } @@ -360,34 +764,36 @@ public class ToolScaffolder { String useCase = Files.readString(useCaseFile, StandardCharsets.UTF_8); String implementation = Files.readString(useCaseImplFile, StandardCharsets.UTF_8); for (ToolMethodDefinition tool : tools) { - String baseName = toPascalCase(tool.baseName()); + boolean mci = "MCI".equalsIgnoreCase(tool.routingType()); + String toolBaseName = toPascalCase(tool.baseName()); + String baseName = mci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; String methodName = tool.methodName(); - String toolName = toToolName(moduleName, tool.group(), baseName); + String toolName = toToolName(moduleName, tool.group(), toolBaseName); if (useCase.matches("(?s).*\\b" + java.util.regex.Pattern.quote(methodName) + "\\s*\\(.*") || useCase.contains("name = \"" + toolName + "\"")) { throw new IllegalArgumentException("Tool method or MCP Tool name already exists: " + methodName); } - boolean mci = "MCI".equalsIgnoreCase(tool.routingType()); - String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + (tool.clientSystemCode().length() == 4 ? tool.clientSystemCode().substring(0,3).toLowerCase(Locale.ROOT) + "." + tool.clientSystemCode().substring(3).toLowerCase(Locale.ROOT) : tool.clientSystemCode().toLowerCase(Locale.ROOT)) + String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + formatClientSystemCode(tool.clientSystemCode(), ".") : ".infra.itrf.http." + toPackageSegment(tool.httpApiName())); String requestType = baseName + "Request"; String responseType = baseName + "Response"; - String requestIo = mci ? tool.interfaceId() + "_I" : baseName + "HttpRequest"; - String responseIo = mci ? tool.interfaceId() + "_O" : baseName + "HttpResponse"; + String ioPrefix = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) ? tool.clientSystemCode().toUpperCase() : tool.interfaceId(); + String requestIo = mci ? ioPrefix + "_I" : baseName + "HttpRequest"; + String responseIo = mci ? ioPrefix + "_O" : baseName + "HttpResponse"; useCase = addImport(useCase, "import " + bizPackage + ".dto." + requestType + ";") ; useCase = addImport(useCase, "import " + bizPackage + ".dto." + responseType + ";") ; boolean isMutation = isMutationTool(baseName); ToolDefinitionOptions opts = tool.definitionOptions() == null ? new ToolDefinitionOptions(null, null, null, null, null, null, null, null) : tool.definitionOptions(); - + StringBuilder declBuilder = new StringBuilder("\n @McpTool(name = \"").append(toolName) .append("\", title = \"").append(javaText(option(tool.title(), baseName))) .append("\", description = \"").append(javaText(option(tool.description(), ""))).append("\")\n") .append(" @GrowToolHint(\n") .append(" requiresApproval = ").append(isMutation).append(",\n") .append(" categoryKey = \"").append(tool.group().toLowerCase(Locale.ROOT)).append("\",\n") - .append(" timeoutMillis = 5000L,\n") - .append(" retryMaxAttempts = 3,\n"); + .append(" timeoutMillis = ").append(opts.timeoutMillisOrDefault()).append("L,\n") + .append(" retryMaxAttempts = ").append(opts.retryMaxAttemptsOrDefault()).append(",\n"); String mappingId = option(tool.interfaceId(), tool.httpApiName()); if (mappingId != null && !mappingId.isBlank()) { declBuilder.append(" mappingId = \"").append(javaText(mappingId)).append("\",\n"); @@ -397,7 +803,7 @@ public class ToolScaffolder { .append(" whenNotToUse = \"").append(javaText(opts.whenNotToUse() != null && !opts.whenNotToUse().isBlank() ? opts.whenNotToUse() : "정보 변경이나 실행 작업에는 사용하지 않습니다.")).append("\",\n") .append(" ioLimits = \"").append(javaText(opts.ioLimits() != null && !opts.ioLimits().isBlank() ? opts.ioLimits() : "정의된 입력 항목만 허용하며 업무 결과만 반환합니다.")).append("\",\n") .append(" displayDescription = \"").append(javaText(opts.displayDescription() != null && !opts.displayDescription().isBlank() ? opts.displayDescription() : option(tool.title(), baseName) + " 정보를 처리합니다.")).append("\",\n"); - + List examples = opts.exampleQueries(); if (examples == null || examples.isEmpty()) { examples = List.of(option(tool.title(), baseName) + " 정보를 보여줘", option(tool.title(), baseName) + " 확인해줘", "현재 " + option(tool.title(), baseName) + " 알려줘"); @@ -407,7 +813,7 @@ public class ToolScaffolder { .append("},\n") .append(" destructive = ").append(isMutation).append(",\n") .append(" idempotent = ").append(!isMutation).append(",\n"); - + List tags = opts.tags(); if (tags == null || tags.isEmpty()) { tags = List.of(tool.group().toLowerCase(Locale.ROOT), isMutation ? "처리" : "조회"); @@ -418,51 +824,119 @@ public class ToolScaffolder { .append(" ownerOrg = \"").append(javaText(opts.ownerOrg() != null && !opts.ownerOrg().isBlank() ? opts.ownerOrg() : "MCP_TOOL")).append("\"\n") .append(" )\n") .append(" ").append(responseType).append(" ").append(methodName).append("(").append(requestType).append(" req);\n"); - + String declaration = declBuilder.toString(); useCase = insertBeforeLastBrace(useCase, declaration); - String clientClassName; - String clientVariable; - if (mci) { - String sysCode = tool.clientSystemCode().toLowerCase(Locale.ROOT); - clientClassName = "Mci" + sysCode.substring(0, 1).toUpperCase(Locale.ROOT) + sysCode.substring(1) + "Client"; - clientVariable = "mci" + sysCode.substring(0, 1).toUpperCase(Locale.ROOT) + sysCode.substring(1) + "Client"; - } else { - clientClassName = baseName + "Client"; - clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; - } - String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter"; + ToolDefinitionOptions options = tool.definitionOptions() == null + ? new ToolDefinitionOptions(null, null, null, null, null, List.of(), List.of(), null) + : tool.definitionOptions(); + PagingMode pagingMode = mci ? options.pagingModeOrNone() : PagingMode.NONE; - implementation = addImport(implementation, "import " + bizPackage + ".dto." + requestType + ";"); - implementation = addImport(implementation, "import " + bizPackage + ".dto." + responseType + ";"); - implementation = addImport(implementation, "import " + bizPackage + ".converter." + baseName + "Converter;"); - implementation = addImport(implementation, "import " + integrationPackage + "." + clientClassName + ";"); - implementation = addImport(implementation, "import " + integrationPackage + ".io." + requestIo + ";"); - implementation = addImport(implementation, "import " + integrationPackage + ".io." + responseIo + ";"); - implementation = addImport(implementation, "import lombok.RequiredArgsConstructor;"); - if (!implementation.contains("@RequiredArgsConstructor")) { - implementation = implementation.replaceFirst("public class ", "@RequiredArgsConstructor\npublic class "); + if (pagingMode != PagingMode.NONE) { + String pagingSuffix = pagingMode == PagingMode.SCROLL ? "ScrollPaging" : "PageNumberPaging"; + String pagingInfoType = pagingMode == PagingMode.SCROLL ? "ScrollPagingInfo" : "PgNumPagingInfo"; + String pagingInterface = baseName + pagingSuffix; + String pagingVar = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + pagingSuffix; + + implementation = addImport(implementation, "import " + bizPackage + ".dto." + requestType + ";"); + implementation = addImport(implementation, "import " + bizPackage + ".dto." + responseType + ";"); + implementation = addImport(implementation, "import " + bizPackage + ".paging." + pagingInterface + ";"); + implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging.MciPage;"); + implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging." + pagingInfoType + ";"); + implementation = addImport(implementation, "import lombok.extern.slf4j.Slf4j;"); + if (!implementation.contains("@Slf4j")) { + implementation = implementation.replaceFirst("public class ", "@Slf4j\npublic class "); + } + implementation = addImport(implementation, "import lombok.RequiredArgsConstructor;"); + if (!implementation.contains("@RequiredArgsConstructor")) { + implementation = implementation.replaceFirst("public class ", "@RequiredArgsConstructor\npublic class "); + } + if (!implementation.contains(" " + pagingVar + ";")) { + implementation = insertConstructorField(implementation, " private final " + pagingInterface + " " + pagingVar + ";"); + } + String method = groupedToolPagingMethodContent(tool, baseName, pagingVar, pagingMode, pagingInfoType); + implementation = insertBeforeLastBrace(implementation, method); + if (!implementation.contains("mergeResponseData(")) { + implementation = insertBeforeLastBrace(implementation, """ + + private void mergeResponseData(Object target, Object src) { + if (target == null || src == null) return; + for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { + if (java.util.List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + java.util.List srcList = (java.util.List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + java.util.List targetList = (java.util.List) field.get(target); + if (targetList == null) { + targetList = new java.util.ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof java.util.ArrayList)) { + targetList = new java.util.ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + } + """); + } + } else { + String clientClassName; + String clientVariable; + if (mci) { + clientClassName = mciClientClassName(tool.clientSystemCode()); + clientVariable = "mci"; + } else { + clientClassName = baseName + "Client"; + clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; + } + String targetPkg = mci ? mciTargetSystemPackage(tool.clientSystemCode()) : null; + String converterPkg = bizPackage + ".converter" + (targetPkg != null ? "." + targetPkg : ""); + String converterName = (mci && tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) + ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" + : baseName + "Converter"; + String converterVariable = "converter"; + + implementation = addImport(implementation, "import " + bizPackage + ".dto." + requestType + ";"); + implementation = addImport(implementation, "import " + bizPackage + ".dto." + responseType + ";"); + implementation = addImport(implementation, "import " + converterPkg + "." + converterName + ";"); + implementation = addImport(implementation, "import " + integrationPackage + "." + clientClassName + ";"); + implementation = addImport(implementation, "import " + integrationPackage + ".io." + requestIo + ";"); + implementation = addImport(implementation, "import " + integrationPackage + ".io." + responseIo + ";"); + if (mci) { + implementation = addImport(implementation, "import io.shinhanlife.glow.communication.dto.Transfer;"); + implementation = addImport(implementation, "import lombok.extern.slf4j.Slf4j;"); + if (!implementation.contains("@Slf4j")) { + implementation = implementation.replaceFirst("public class ", "@Slf4j\npublic class "); + } + } + implementation = addImport(implementation, "import lombok.RequiredArgsConstructor;"); + if (!implementation.contains("@RequiredArgsConstructor")) { + implementation = implementation.replaceFirst("public class ", "@RequiredArgsConstructor\npublic class "); + } + if (!implementation.contains(" " + clientVariable + ";")) { + implementation = insertConstructorField(implementation, " private final " + clientClassName + " " + clientVariable + ";"); + } + if (!implementation.contains(" " + converterVariable + ";")) { + implementation = insertConstructorField(implementation, " private final " + converterName + " " + converterVariable + ";"); + } + String method = groupedToolMethodContent(tool, baseName, converterVariable, clientVariable, ioPrefix, mci); + implementation = insertBeforeLastBrace(implementation, method); } - if (!implementation.contains(" " + clientVariable + ";")) { - implementation = insertConstructorField(implementation, " private final " + clientClassName + " " + clientVariable + ";"); - } - implementation = insertConstructorField(implementation, " private final " + baseName + "Converter " + converterVariable + ";"); - String call = mci - ? clientVariable + ".callTo(\"" + tool.interfaceId() + "\", null, request, " + responseIo + ".class).getBody()" - : clientVariable + ".call(request, " + responseIo + ".class)"; - String method = "\n @Override\n public " + responseType + " " + methodName + "(" + requestType + " req) {\n" - + " " + requestIo + " request = " + converterVariable + ".toRequest(req);\n" - + " " + responseIo + " response = " + call + ";\n" - + " " + responseType + " toolResponse = " + converterVariable + ".toResponse(response);\n" - + " if (toolResponse == null) toolResponse = new " + responseType + "();\n" - + " toolResponse.setResultCode(\"SUCCESS\");\n" - + " return toolResponse;\n }\n"; - implementation = insertBeforeLastBrace(implementation, method); } writeUtf8(useCaseFile, useCase); writeUtf8(useCaseImplFile, implementation); - if (!Files.exists(converterFile)) { + boolean hasMci = tools.stream().anyMatch(t -> "MCI".equalsIgnoreCase(t.routingType())); + if (!hasMci && !Files.exists(converterFile)) { writeUtf8(converterFile, groupedConverterContent(bizPackage, useCaseBaseName, tools)); } } @@ -522,40 +996,22 @@ public class ToolScaffolder { return value == null ? "" : value.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", " ").replace("\n", " "); } - /** - * 콘솔 Scaffold에서 LLM 설명 대신 업무 단위의 제안서를 입력할 수 있도록 안내한다. - */ - public static String businessProposalGuide() { - return """ - \n[업무 제안서 작성 가이드] - Tool 이름만 적지 말고, 아래 항목을 한두 문장씩 포함해 작성하세요. - 1. 조회 대상·식별 기준: 무엇을 어떤 값으로 찾는지 - 2. 조회 목적·사용자: 누가 어떤 업무 상황에서 쓰는지 - 3. 조회 범위·결과 단위: 목록인지 상세인지, 반드시 필요한 정보는 무엇인지 - 4. 조건·예외: 기준일, 포함/제외 조건, 식별값 부족·다건 조회 시 처리 - 5. 권한·마스킹 및 제외 범위: 노출하면 안 되는 정보와 별도 Tool로 분리할 업무 - - [통합계약원부 조회 제안서 예시] - 상담사가 고객의 현재 유효 계약을 확인한다. 계약번호가 있으면 상세 원부를 조회하고, - 없으면 고객 식별값으로 계약 목록을 먼저 조회한다. 계약 기본정보, 계약자·피보험자, - 주계약·특약, 납입 상태와 실효 여부를 반환한다. 계약이 여러 건이면 목록을 먼저 반환하고, - 주민번호와 계좌번호는 마스킹한다. 해지·대출·보험금 상세는 별도 Tool로 분리한다. - """; - } - public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); + System.out.println("========================================="); + System.out.println(" MCP Tool Scaffolder (Java CLI) "); + System.out.println("=========================================\n"); + String baseName = getOrAsk(args, 0, scanner, "1. 생성할 Tool의 기본 이름 (예: ExchangeRate) [영문 PascalCase]: "); String interfaceId = getOrAsk(args, 1, scanner, "2. 레거시 API 인터페이스 ID (예: EXCH_001): "); String title = getOrAsk(args, 2, scanner, "3. Tool title: "); - System.out.println(businessProposalGuide()); - String description = getOrAsk(args, 3, scanner, "4. 업무 제안서 (생성 Tool의 LLM 설명으로 사용): "); + String description = getOrAsk(args, 3, scanner, "4. Tool description for LLM: "); String group = getOrAsk(args, 4, scanner, "5. Tool category: "); if (group.isEmpty()) group = "COMMON"; String routingType = getOrAsk(args, 5, scanner, "6. Routing type (HTTP, TCP, MCI, EAI): "); if (routingType.trim().isEmpty()) { - routingType = "HTTP"; + routingType = "MCI"; } String moduleName = getOrAsk(args, 6, scanner, "7. Target module (default dat-was-cus): "); if (moduleName.trim().isEmpty()) { @@ -576,7 +1032,7 @@ public class ToolScaffolder { String schemaResourceDirectory = "classpath:tool-schemas/" + group.toLowerCase() + "/"; String inputSchemaResource = useSchemaResource ? schemaResourceDirectory + toKebabCase(baseName) + "-resource-input-schema.json" : null; String outputSchemaResource = useSchemaResource ? schemaResourceDirectory + toKebabCase(baseName) + "-resource-output-schema.json" : null; - String defaultWorkspace = "c:\\eGovFrameDev-4.3.1-64bit\\workspace-egov\\dat-was-datmt"; + String defaultWorkspace = "C:\\eGovFrameDev-4.3.1-64bit\\workspace-egov\\dat-was-dasmt"; String workspace = getOrAsk(args, 10, scanner, "11. 대상 프로젝트 워크스페이스 경로 (default: " + defaultWorkspace + "): "); if (workspace.trim().isEmpty()) { workspace = defaultWorkspace; @@ -584,12 +1040,14 @@ public class ToolScaffolder { System.setProperty("AXHUB_SOURCE_DIR", workspace); String result = scaffold(baseName, interfaceId, title, description, group, routingType, moduleName, author, createDate, false, null, inputSchemaResource, outputSchemaResource, List.of(new FieldDefinition("query", "String", "Search query", List.of("example"), "", false)), List.of()); + System.out.println(result); } private static String getOrAsk(String[] args, int index, Scanner scanner, String prompt) { if (args.length > index) { return args[index]; } + System.out.print(prompt); return scanner.nextLine().trim(); } @@ -633,13 +1091,36 @@ public class ToolScaffolder { String outputSchemaResource, List inputFields, List outputFields, String httpApiName, ToolDefinitionOptions definitionOptions) throws IOException { - baseName = toPascalCase(baseName); - title = title == null || title.isBlank() ? baseName : title.trim(); - description = description == null ? "" : description.trim(); - httpApiName = httpApiName == null || httpApiName.isBlank() ? toKebabCase(baseName) : httpApiName.trim(); - if (definitionOptions == null) { - definitionOptions = new ToolDefinitionOptions(null, null, null, null, null, null, null, null); + return scaffoldWithAbbreviatedMciSources(baseName, interfaceId, title, description, group, routingType, + moduleName, author, createDate, register, clientSystemCode, inputSchemaResource, + outputSchemaResource, inputFields, outputFields, httpApiName, definitionOptions); + } + + /** + * Generates MCI source files from an abbreviation derived from the Base Name. The Base Name remains the MCP Tool name. + */ + private static String scaffoldWithAbbreviatedMciSources(String baseName, String interfaceId, String title, + String description, String group, String routingType, + String moduleName, String author, String createDate, + boolean register, String clientSystemCode, + String inputSchemaResource, String outputSchemaResource, + List inputFields, + List outputFields, String httpApiName, + ToolDefinitionOptions definitionOptions) throws IOException { + boolean isMci = "MCI".equalsIgnoreCase(routingType); + boolean isHttp = "HTTP".equalsIgnoreCase(routingType); + if (!isMci && !isHttp) { + throw new IllegalArgumentException("Unsupported routing type: " + routingType + ". Only MCI and HTTP are supported."); } + String toolBaseName = toPascalCase(baseName); + baseName = isMci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; + title = title == null || title.isBlank() ? toolBaseName : title.trim(); + description = description == null ? "" : description.trim(); + definitionOptions = definitionOptions == null + ? new ToolDefinitionOptions(null, null, null, null, null, List.of(), List.of(), null) + : definitionOptions; + PagingMode pagingMode = isMci ? definitionOptions.pagingModeOrNone() : PagingMode.NONE; + httpApiName = httpApiName == null || httpApiName.isBlank() ? toKebabCase(toolBaseName) : httpApiName.trim(); String envSourceDir = System.getProperty("AXHUB_SOURCE_DIR"); if (envSourceDir == null) { envSourceDir = System.getenv("AXHUB_SOURCE_DIR"); @@ -651,11 +1132,10 @@ public class ToolScaffolder { Path dtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "dto")); Path legacyDtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "legacy")); - Path converterDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "converter")); // Schema Resource 파일 경로(useSchemaResource=true일 때만 생성) boolean useSchemaResource = (inputSchemaResource != null && !inputSchemaResource.trim().isEmpty()) || (outputSchemaResource != null && !outputSchemaResource.trim().isEmpty()); - String schemaBaseName = toKebabCase(baseName); + String schemaBaseName = toKebabCase(toolBaseName); String inputSchemaFileName = schemaBaseName + "-resource-input-schema.json"; String outputSchemaFileName = schemaBaseName + "-resource-output-schema.json"; Path schemaDir = rootDir.resolve(Paths.get(moduleName, "src/main/resources/tool-schemas", group.toLowerCase())); @@ -664,22 +1144,33 @@ public class ToolScaffolder { String outputSchemaClasspath = "classpath:tool-schemas/" + group.toLowerCase() + "/" + outputSchemaFileName; String bizPackage = BASE_PACKAGE + ".biz." + group.toLowerCase(); - boolean isMci = "MCI".equalsIgnoreCase(routingType); - boolean isHttp = "HTTP".equalsIgnoreCase(routingType); - if (!isMci && !isHttp) { - throw new IllegalArgumentException("Unsupported routing type: " + routingType + ". Only MCI and HTTP are supported."); - } + String ioPrefix = (clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : interfaceId; String mciGroupPath = "infra/itrf/mci/" + group.toLowerCase(); String clientPrefixCap = ""; Path mciClientDir = null; - if (isMci && clientSystemCode != null && clientSystemCode.length() == 4) { - String clientPrefix = clientSystemCode.toLowerCase(); - clientPrefixCap = toPascalCase(clientSystemCode); + if (isMci && clientSystemCode != null && (clientSystemCode.length() == 4 || clientSystemCode.length() == 9)) { + String clientPrefix = clientSystemCode.length() == 9 ? clientSystemCode.substring(1, 5).toLowerCase() : clientSystemCode.toLowerCase(); + clientPrefixCap = toPascalCase(clientPrefix); mciGroupPath = "infra/itrf/mci/" + clientPrefix.substring(0, 3) + "/" + clientPrefix.substring(3); mciClientDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath)); } + String converterPackage = bizPackage + ".converter"; + String targetSystemPackage = isMci ? mciTargetSystemPackage(clientSystemCode) : null; + if (targetSystemPackage != null) { + converterPackage += "." + targetSystemPackage; + } + String converterClassName = (isMci && clientSystemCode != null && !clientSystemCode.isBlank()) + ? clientSystemCode.toUpperCase(Locale.ROOT) + "Converter" + : baseName + "Converter"; + Path converterDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "converter")); + if (targetSystemPackage != null) { + for (String segment : targetSystemPackage.split("\\.")) { + converterDir = converterDir.resolve(segment); + } + } + Path mciIoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath, "io")); String httpApiPackage = toPackageSegment(httpApiName); String httpApiClass = toPascalCase(httpApiName); @@ -701,8 +1192,14 @@ public class ToolScaffolder { Files.createDirectories(legacyDtoDir); } Files.createDirectories(converterDir); - StringBuilder log = new StringBuilder(); + if (pagingMode != PagingMode.NONE) { + Path pagingDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(Locale.ROOT), "paging")); + String clientCls = clientPrefixCap.isEmpty() ? "AxhubMciComponent" : "Mci" + clientPrefixCap + "Client"; + String recSvcId = (clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase(Locale.ROOT) : ""; + writePagingComponents(pagingDir, bizPackage, baseName, pagingMode, BASE_PACKAGE + "." + mciGroupPath.replace("/", "."), ioPrefix, clientCls, converterPackage, converterClassName, interfaceId, recSvcId); + log.append("Generated ").append(pagingMode).append(" paging components for ").append(baseName).append(".\n"); + } // Generate Request DTO String reqContent = """ @@ -743,7 +1240,7 @@ public class ToolScaffolder { .replaceAll("(?m)^\\s*-\\(\\?:[^\\r\\n]*\\R", "") .replace("private String phoneNumber;", "@Schema(example = \"01012345678\")\n private String phoneNumber;") .replace("private String message;", "@Schema(example = \"테스트 메시지입니다.\")\n private String message;"); - reqContent = dtoContent(bizPackage + ".dto", baseName + "Request", inputFields, author, createDate, true); + reqContent = dtoContent(bizPackage + ".dto", baseName + "Request", inputFields, author, createDate, true, pagingMode); writeUtf8(dtoDir.resolve(baseName + "Request.java"), reqContent); writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Request", inputFields); @@ -778,13 +1275,13 @@ public class ToolScaffolder { // TODO: Add response fields here. Do not include PII in the Tool response. } """.formatted(bizPackage, bizPackage, baseName, author, createDate, createDate, author, baseName); - resContent = dtoContent(bizPackage + ".dto", baseName + "Response", outputFields, author, createDate, false); + resContent = dtoContent(bizPackage + ".dto", baseName + "Response", outputFields, author, createDate, false, pagingMode); writeUtf8(dtoDir.resolve(baseName + "Response.java"), resContent); writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Response", outputFields); - String toolName = toToolName(moduleName, group, baseName); + String toolName = toToolName(moduleName, group, toolBaseName); - boolean isMutation = isMutationTool(baseName); + boolean isMutation = isMutationTool(toolBaseName); StringBuilder sb = new StringBuilder(" @GrowToolHint(\n"); if (useSchemaResource) { sb.append(" inputSchemaResource = \"").append(inputSchemaClasspath).append("\",\n"); @@ -792,8 +1289,8 @@ public class ToolScaffolder { } sb.append(" requiresApproval = ").append(isMutation).append(",\n"); sb.append(" categoryKey = \"").append(group.toLowerCase(Locale.ROOT)).append("\",\n"); - sb.append(" timeoutMillis = 5000L,\n"); - sb.append(" retryMaxAttempts = 3,\n"); + sb.append(" timeoutMillis = ").append(definitionOptions.timeoutMillisOrDefault()).append("L,\n"); + sb.append(" retryMaxAttempts = ").append(definitionOptions.retryMaxAttemptsOrDefault()).append(",\n"); if (interfaceId != null && !interfaceId.isBlank()) { sb.append(" mappingId = \"").append(interfaceId).append("\",\n"); } @@ -802,26 +1299,26 @@ public class ToolScaffolder { sb.append(" whenNotToUse = \"").append(javaText(definitionOptions.whenNotToUse() != null && !definitionOptions.whenNotToUse().isBlank() ? definitionOptions.whenNotToUse() : "정보 변경이나 실행 작업에는 사용하지 않습니다.")).append("\",\n"); sb.append(" ioLimits = \"").append(javaText(definitionOptions.ioLimits() != null && !definitionOptions.ioLimits().isBlank() ? definitionOptions.ioLimits() : "정의된 입력 항목만 허용하며 업무 결과만 반환합니다.")).append("\",\n"); sb.append(" displayDescription = \"").append(javaText(definitionOptions.displayDescription() != null && !definitionOptions.displayDescription().isBlank() ? definitionOptions.displayDescription() : title + " 정보를 처리합니다.")).append("\",\n"); - + List examples = definitionOptions.exampleQueries(); if (examples == null || examples.isEmpty()) { examples = List.of(title + " 정보를 보여줘", title + " 확인해줘", "현재 " + title + " 알려줘"); } sb.append(" exampleQueries = {") - .append(examples.stream().map(q -> "\"" + javaText(q) + "\"").collect(Collectors.joining(", "))) - .append("},\n"); - + .append(examples.stream().map(q -> "\"" + javaText(q) + "\"").collect(Collectors.joining(", "))) + .append("},\n"); + sb.append(" destructive = ").append(isMutation).append(",\n"); sb.append(" idempotent = ").append(!isMutation).append(",\n"); - + List tags = definitionOptions.tags(); if (tags == null || tags.isEmpty()) { tags = List.of(group.toLowerCase(Locale.ROOT), isMutation ? "처리" : "조회"); } sb.append(" tags = {") - .append(tags.stream().map(t -> "\"" + javaText(t) + "\"").collect(Collectors.joining(", "))) - .append("},\n"); - + .append(tags.stream().map(t -> "\"" + javaText(t) + "\"").collect(Collectors.joining(", "))) + .append("},\n"); + sb.append(" ownerOrg = \"").append(javaText(definitionOptions.ownerOrg() != null && !definitionOptions.ownerOrg().isBlank() ? definitionOptions.ownerOrg() : "MCP_TOOL")).append("\"\n"); sb.append(" )"); String toolHintLine = sb.toString(); @@ -865,11 +1362,314 @@ public class ToolScaffolder { baseName, baseName ); + String methodName = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1); + serviceInterfaceContent = serviceInterfaceContent.replace("execute(", methodName + "("); writeUtf8(usecaseDir.resolve(baseName + "UseCase.java"), serviceInterfaceContent); String serviceImplContent; - if (isMci) { + if (isMci && pagingMode != PagingMode.NONE) { + String pagingSuffix = pagingMode == PagingMode.SCROLL ? "ScrollPaging" : "PageNumberPaging"; + String pagingInterface = baseName + pagingSuffix; + if (pagingMode == PagingMode.PAGE_NUMBER) { + serviceImplContent = """ + package %s.usecase.impl; + + import %s.dto.%sRequest; + import %s.dto.%sResponse; + import %s.usecase.%sUseCase; + import %s.paging.%s; + import io.shinhanlife.dat.lib.paging.MciPage; + import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; + import io.shinhanlife.glow.BizException; + import org.springframework.stereotype.Service; + import lombok.RequiredArgsConstructor; + import lombok.extern.slf4j.Slf4j; + + /** + * @package %s.usecase.impl + * @className %sUseCaseImpl + * @description AX HUB 시스템 처리 클래스 + * @author %s + * @create %s + *
+                     * ---------- 개정이력 ----------
+                     * 수정일      수정자    수정내용
+                     * ---------- -------- ---------------------------
+                     * %s  %s    최초생성
+                     *
+                     * 
+ */ + @Slf4j + @Service + @RequiredArgsConstructor + public class %sUseCaseImpl implements %sUseCase { + + private final %s paging; + + @Override + public %sResponse execute(%sRequest req) { + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); + try { + PgNumPagingInfo pagingInfo = null; + PgNumPagingInfo pagingInfoLast = null; + %sResponse finalResponse = null; + int loopCount = 0; + final int MAX_PAGING_COUNT = 10; + boolean hasMore = false; + + while (loopCount < MAX_PAGING_COUNT) { + loopCount++; + MciPage<%sResponse, PgNumPagingInfo> page = paging.fetch(req, pagingInfo); + pagingInfoLast = page.pagingInfo(); + if (finalResponse == null) { + finalResponse = page.data(); + } else if (page.data() != null) { + mergeResponseData(finalResponse, page.data()); + } + if (!page.hasNext()) { + hasMore = false; + break; + } + hasMore = true; + pagingInfo = page.pagingInfo(); + } + + if (finalResponse == null) { + finalResponse = new %sResponse(); + } + finalResponse.setResultCode("SUCCESS"); + finalResponse.setHasMore(hasMore); + if (pagingInfoLast != null) { + int lastPageNo = Math.max(1, pagingInfoLast.getPageNo() - 1); + finalResponse.setPageNo(lastPageNo); + finalResponse.setTotalPageCount(pagingInfoLast.getTotaPageCn()); + finalResponse.setTotalCount(pagingInfoLast.getTotaPageDataCc()); + } else { + finalResponse.setPageNo(1); + finalResponse.setTotalPageCount(1); + } + if (hasMore) { + finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (현재 " + finalResponse.getPageNo() + "페이지 / 총 " + finalResponse.getTotalPageCount() + "페이지, hasMore=true)."); + } else { + finalResponse.setResultMessage("MCI 페이징 조회가 완료되었습니다 (현재 " + finalResponse.getPageNo() + "페이지 / 총 " + finalResponse.getTotalPageCount() + "페이지)."); + } + return finalResponse; + } catch (BizException e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse response = new %sResponse(); + response.setResultCode("ERROR"); + response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); + response.setHasMore(false); + response.setPageNo(1); + response.setTotalPageCount(0); + response.setTotalCount(0); + return response; + } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse response = new %sResponse(); + response.setResultCode("ERROR"); + response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); + response.setHasMore(false); + response.setPageNo(1); + response.setTotalPageCount(0); + response.setTotalCount(0); + return response; + } + } + + private void mergeResponseData(%sResponse target, %sResponse src) { + if (target == null || src == null) return; + for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { + if (java.util.List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + java.util.List srcList = (java.util.List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + java.util.List targetList = (java.util.List) field.get(target); + if (targetList == null) { + targetList = new java.util.ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof java.util.ArrayList)) { + targetList = new java.util.ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + } + } + """.formatted( + bizPackage, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, pagingInterface, + bizPackage, + baseName, + author, + createDate, + createDate, author, + baseName, baseName, + pagingInterface, + baseName, baseName, + toolName, pagingMode, + baseName, + baseName, + baseName, + baseName, baseName, + baseName, baseName, + baseName, baseName + ); + } else { + serviceImplContent = """ + package %s.usecase.impl; + + import %s.dto.%sRequest; + import %s.dto.%sResponse; + import %s.usecase.%sUseCase; + import %s.paging.%s; + import io.shinhanlife.dat.lib.paging.MciPage; + import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; + import io.shinhanlife.glow.BizException; + import org.springframework.stereotype.Service; + import lombok.RequiredArgsConstructor; + import lombok.extern.slf4j.Slf4j; + + /** + * @package %s.usecase.impl + * @className %sUseCaseImpl + * @description AX HUB 시스템 처리 클래스 + * @author %s + * @create %s + *
+                     * ---------- 개정이력 ----------
+                     * 수정일      수정자    수정내용
+                     * ---------- -------- ---------------------------
+                     * %s  %s    최초생성
+                     *
+                     * 
+ */ + @Slf4j + @Service + @RequiredArgsConstructor + public class %sUseCaseImpl implements %sUseCase { + + private final %s paging; + + @Override + public %sResponse execute(%sRequest req) { + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); + try { + ScrollPagingInfo pagingInfo = null; + %sResponse finalResponse = null; + int loopCount = 0; + final int MAX_PAGING_COUNT = 10; + boolean hasMore = false; + + while (loopCount < MAX_PAGING_COUNT) { + loopCount++; + MciPage<%sResponse, ScrollPagingInfo> page = paging.fetch(req, pagingInfo); + if (finalResponse == null) { + finalResponse = page.data(); + } else if (page.data() != null) { + mergeResponseData(finalResponse, page.data()); + } + if (!page.hasNext()) { + hasMore = false; + break; + } + hasMore = true; + pagingInfo = page.pagingInfo(); + } + + if (finalResponse == null) { + finalResponse = new %sResponse(); + } + finalResponse.setResultCode("SUCCESS"); + finalResponse.setHasMore(hasMore); + if (hasMore) { + finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (총 " + loopCount + "회 호출, hasMore=true)."); + } else { + finalResponse.setResultMessage("MCI 스크롤 페이징 조회가 완료되었습니다 (총 " + loopCount + "회 호출)."); + } + return finalResponse; + } catch (BizException e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse response = new %sResponse(); + response.setResultCode("ERROR"); + response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); + response.setHasMore(false); + return response; + } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse response = new %sResponse(); + response.setResultCode("ERROR"); + response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); + response.setHasMore(false); + return response; + } + } + + private void mergeResponseData(%sResponse target, %sResponse src) { + if (target == null || src == null) return; + for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { + if (java.util.List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + java.util.List srcList = (java.util.List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + java.util.List targetList = (java.util.List) field.get(target); + if (targetList == null) { + targetList = new java.util.ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof java.util.ArrayList)) { + targetList = new java.util.ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + } + } + """.formatted( + bizPackage, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, pagingInterface, + bizPackage, + baseName, + author, + createDate, + createDate, author, + baseName, baseName, + pagingInterface, + baseName, baseName, + toolName, pagingMode, + baseName, + baseName, + baseName, + baseName, baseName, + baseName, baseName, + baseName, baseName + ); + } + } else if (isMci) { serviceImplContent = """ package %s.usecase.impl; @@ -878,11 +1678,13 @@ public class ToolScaffolder { import %s.usecase.%sUseCase; import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent; import io.shinhanlife.glow.communication.dto.Transfer; + import io.shinhanlife.glow.BizException; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; - import %s.converter.%sConverter; + import %s.%s; import %s.%s.io.%s_I; + import %s.%s.io.%s_O; %s /** @@ -893,10 +1695,10 @@ public class ToolScaffolder { * @create %s *
                  * ---------- 개정이력 ----------
-                 * 수정일       수정자     수정내용
+                 * 수정일      수정자    수정내용
                  * ---------- -------- ---------------------------
                  * %s  %s    최초생성
-                 * 
+                 *
                  * 
*/ @Slf4j @@ -905,7 +1707,7 @@ public class ToolScaffolder { public class %sUseCaseImpl implements %sUseCase { %s - private final %sConverter converter; + private final %s converter; @Override public %sResponse execute(%sRequest req) { @@ -913,19 +1715,33 @@ public class ToolScaffolder { try { // MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO) %s_I mciReq = converter.toLegacyRequest(req); + Transfer<%s_O> resTransfer = null; + + if (mciReq != null) { + resTransfer = mci.callTo( + "%s", + "%s", + mciReq, + %s_O.class + ); + } - Transfer resTransfer = mci.callTo( - "%s", - null, - mciReq, - Object.class - ); %sResponse response = new %sResponse(); + if (resTransfer != null && resTransfer.getBody() != null) { + response = converter.toResponse(resTransfer.getBody()); + } + response.setResultCode("SUCCESS"); - response.setResultMessage(resTransfer.getBody() != null + response.setResultMessage(resTransfer != null && resTransfer.getBody() != null ? "MCI call completed." : "MCI call completed without a response body."); return response; + } catch (BizException e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); + %sResponse response = new %sResponse(); + response.setResultCode("ERROR"); + response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error"); + return response; } catch (Exception e) { log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); %sResponse response = new %sResponse(); @@ -940,8 +1756,9 @@ public class ToolScaffolder { bizPackage, baseName, bizPackage, baseName, bizPackage, baseName, - bizPackage, baseName, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, + converterPackage, converterClassName, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, (clientPrefixCap.isEmpty() ? "" : "import " + BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".Mci" + clientPrefixCap + "Client;\n"), bizPackage, baseName, @@ -951,25 +1768,22 @@ public class ToolScaffolder { baseName, baseName, (clientPrefixCap.isEmpty() ? "private final AxhubMciComponent mci;" : "private final Mci" + clientPrefixCap + "Client mci;"), - baseName, + converterClassName, baseName, baseName, toolName, + ioPrefix, + ioPrefix, interfaceId, - interfaceId, + ((clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : ""), + ioPrefix, + baseName, + baseName, baseName, baseName, baseName, baseName ); - String mciIoPackage = BASE_PACKAGE + "." + mciGroupPath.replace("/", "."); - serviceImplContent = serviceImplContent - .replace("import " + mciIoPackage + ".io." + interfaceId + "_I;", - "import " + mciIoPackage + ".io." + interfaceId + "_I;\nimport " + mciIoPackage + ".io." + interfaceId + "_O;") - .replace("Transfer resTransfer", "Transfer<" + interfaceId + "_O> resTransfer") - .replace("Object.class", interfaceId + "_O.class") - .replace("response.setResultCode(\"SUCCESS\");", - "if (resTransfer.getBody() != null) {\n response = converter.toResponse(resTransfer.getBody());\n }\n response.setResultCode(\"SUCCESS\");"); } else { serviceImplContent = isHttp ? httpUseCaseImplContent(bizPackage, baseName, httpGroupPath.replace("/", "."), httpApiClass, author, createDate) @@ -1040,9 +1854,11 @@ public class ToolScaffolder { ); } + serviceImplContent = serviceImplContent.replace("execute(", methodName + "("); writeUtf8(usecaseImplDir.resolve(baseName + "UseCaseImpl.java"), serviceImplContent); if (isMci) { + String mciReqContent = """ package %s.%s.io; @@ -1064,6 +1880,7 @@ public class ToolScaffolder { */ @Data public class %s_I { + // TODO: Add request fields here /** * EAI 시스템이 요구하는 수신자 번호 파라미터명 */ @@ -1074,10 +1891,10 @@ public class ToolScaffolder { */ private String content; } - """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId); - mciReqContent = mciIoContent(mciGroupPath.replace("/", "."), interfaceId + "_I", inputFields, author, createDate); - writeUtf8(mciIoDir.resolve(interfaceId + "_I.java"), mciReqContent); - writeStructuredFieldTypes(mciIoDir, BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".io", interfaceId + "_I", inputFields); + """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, author, createDate, createDate, author, ioPrefix); + mciReqContent = mciIoContent(mciGroupPath.replace("/", "."), ioPrefix + "_I", inputFields, author, createDate, pagingMode); + writeUtf8(mciIoDir.resolve(ioPrefix + "_I.java"), mciReqContent); + writeStructuredFieldTypes(mciIoDir, BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".io", ioPrefix + "_I", inputFields); String mciResContent = """ package %s.%s.io; @@ -1102,10 +1919,10 @@ public class ToolScaffolder { public class %s_O { // TODO: Add response fields here } - """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId); - mciResContent = mciIoContent(mciGroupPath.replace("/", "."), interfaceId + "_O", outputFields, author, createDate); - writeUtf8(mciIoDir.resolve(interfaceId + "_O.java"), mciResContent); - writeStructuredFieldTypes(mciIoDir, BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".io", interfaceId + "_O", outputFields); + """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, author, createDate, createDate, author, ioPrefix); + mciResContent = mciIoContent(mciGroupPath.replace("/", "."), ioPrefix + "_O", outputFields, author, createDate, pagingMode); + writeUtf8(mciIoDir.resolve(ioPrefix + "_O.java"), mciResContent); + writeStructuredFieldTypes(mciIoDir, BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".io", ioPrefix + "_O", outputFields); String converterContent = """ package %s.converter; @@ -1149,15 +1966,15 @@ public class ToolScaffolder { bizPackage, bizPackage, baseName, bizPackage, baseName, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, bizPackage, baseName, author, createDate, createDate, author, - baseName, interfaceId, baseName, - baseName, interfaceId, - baseName, interfaceId + baseName, ioPrefix, baseName, + baseName, ioPrefix, + baseName, ioPrefix ); - converterContent = mciConverterContent(bizPackage, baseName, mciGroupPath.replace("/", "."), interfaceId); - writeUtf8(converterDir.resolve(baseName + "Converter.java"), converterContent); + converterContent = mciConverterContent(converterPackage, bizPackage, baseName, mciGroupPath.replace("/", "."), ioPrefix, converterClassName); + writeUtf8(converterDir.resolve(converterClassName + ".java"), converterContent); log.append("\n=========================================\n"); log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n"); @@ -1168,17 +1985,20 @@ public class ToolScaffolder { log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n"); log.append("[MCI Request IO] ").append(mciIoDir.resolve(interfaceId + "_I.java")).append("\n"); log.append("[MCI Response IO] ").append(mciIoDir.resolve(interfaceId + "_O.java")).append("\n"); - log.append("[MCI Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n"); + log.append("[MCI Converter] ").append(converterDir.resolve(converterClassName + ".java")).append("\n"); if (!clientPrefixCap.isEmpty()) { + String receiveServiceId = (clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : ""; String mciClientContent = """ package %s.%s; - + import org.springframework.stereotype.Component; import lombok.RequiredArgsConstructor; import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent; import io.shinhanlife.glow.communication.dto.Transfer; - + import %s.%s.io.%s_I; + import %s.%s.io.%s_O; + /** * @package %s.%s * @className Mci%sClient @@ -1190,21 +2010,37 @@ public class ToolScaffolder { * 수정일 수정자 수정내용 * ---------- -------- --------------------------- * %s %s 최초생성 - * + * * */ @Component @RequiredArgsConstructor public class Mci%sClient { - private final AxhubMciComponent mci; - - public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) throws Exception { - return mci.callTo(interfaceId, dummy, mciReq, resType); + + private static final String INTERFACE_ID = "%s"; + private static final String RECEIVE_SERVICE_ID = "%s"; + + private final AxhubMciComponent mciComponent; + + public Transfer callTo(String interfaceId, String receiveServiceId, Object mciReq, Class resType) { + return mciComponent.callTo(interfaceId, receiveServiceId, mciReq, resType); + } + + public %s_O call%s(%s_I request) { + Transfer<%s_O> transfer = mciComponent.callTo( + INTERFACE_ID, RECEIVE_SERVICE_ID, request, %s_O.class); + return transfer == null ? null : transfer.getBody(); } } """.formatted( BASE_PACKAGE, mciGroupPath.replace("/", "."), - BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, clientPrefixCap + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, + clientPrefixCap, + interfaceId, receiveServiceId, + ioPrefix, toPascalCase(ioPrefix), ioPrefix, + ioPrefix, ioPrefix ); writeUtf8(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java"), mciClientContent); log.append("[MCI Client] ").append(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java")).append("\n"); @@ -1402,28 +2238,12 @@ public class ToolScaffolder { log.append("[Output Schema] ").append(schemaDir.resolve(outputSchemaFileName)).append("\n"); } - String mockResponse = mockResponseContent(outputFields); + // Response JSON mock files are intentionally not generated. Runtime response contracts are represented by DTOs. if (isHttp) { Path moduleRoot = rootDir.resolve(moduleName).toAbsolutePath().normalize(); Path projectRoot = moduleRoot.getParent(); - Path wireMockBodyPath = projectRoot.resolve(Paths.get("mci-mock", "__files", toolName + ".json")); - Path wireMockMappingPath = projectRoot.resolve(Paths.get("mci-mock", "mappings", toolName + ".json")); - Path podMockResponsePath = moduleRoot.resolve(Paths.get("src/main/resources/mock-responses", toolName + ".json")); - Files.createDirectories(wireMockBodyPath.getParent()); - Files.createDirectories(wireMockMappingPath.getParent()); - Files.createDirectories(podMockResponsePath.getParent()); - writeUtf8(wireMockBodyPath, mockResponse); - writeUtf8(wireMockMappingPath, wireMockMappingContent(interfaceId, wireMockBodyPath.getFileName().toString())); - writeUtf8(podMockResponsePath, mockResponse); - ensureLocalHttpApiConfiguration(projectRoot, httpApiName, toolName); - log.append("[WireMock Response] ").append(wireMockBodyPath).append("\n"); - log.append("[WireMock Mapping] ").append(wireMockMappingPath).append("\n"); - log.append("[Pod Mock Response] ").append(podMockResponsePath).append("\n"); - } else { - Path mockResponsePath = rootDir.resolve(Paths.get(moduleName, "src/main/resources/mock-responses", toolName + ".json")); - Files.createDirectories(mockResponsePath.getParent()); - writeUtf8(mockResponsePath, mockResponse); - log.append("[Mock Response] ").append(mockResponsePath).append("\n"); + Path glowConfig = ensureLocalHttpApiConfiguration(projectRoot, httpApiName, toolName); + log.append("[HTTP Config] ").append(glowConfig).append("\n"); } Path generatedTestDir = rootDir.resolve(Paths.get(moduleName, "src/test/java/io/shinhanlife/dat/mcc/biz", group.toLowerCase(), "usecase")); @@ -1634,13 +2454,76 @@ public class ToolScaffolder { .toLowerCase(Locale.ROOT); } - private static void ensureLocalHttpApiConfiguration(Path projectRoot, String httpApiName, String toolName) throws IOException { - Path localConfigPath = projectRoot.resolve("src/main/resources/glow/application-glow-local.yml"); + private static Path findGlowLocalConfigPath(Path startPath) { + String sourceDir = System.getProperty("AXHUB_SOURCE_DIR"); + if (sourceDir == null) { + sourceDir = System.getenv("AXHUB_SOURCE_DIR"); + } + + List baseDirs = new ArrayList<>(); + if (startPath != null) { + baseDirs.add(startPath); + if (startPath.getParent() != null) { + baseDirs.add(startPath.getParent()); + } + } + if (sourceDir != null && !sourceDir.isBlank()) { + baseDirs.add(Paths.get(sourceDir.trim())); + } + baseDirs.add(Paths.get(".")); + + String[] subPaths = { + "dat-was-lib/src/main/resources/glow", + "src/main/resources/glow" + }; + String[] fileNames = { + "application-glow-local.yml", + "application-glow-local.yaml", + "application-glow-local.xml" + }; + + // 1. 이미 존재하는 파일 우선 탐색 (dat-was-lib 우선) + for (Path base : baseDirs) { + for (String sub : subPaths) { + for (String name : fileNames) { + Path candidate = base.resolve(sub).resolve(name).normalize(); + if (Files.exists(candidate)) { + return candidate; + } + } + } + } + + // 2. dat-was-lib 디렉토리가 존재하는 디렉토리 찾기 + for (Path base : baseDirs) { + Path libDir = base.resolve("dat-was-lib"); + if (Files.isDirectory(libDir)) { + return libDir.resolve("src/main/resources/glow/application-glow-local.yml").normalize(); + } + } + + // 3. startPath 형제(sibling)로 dat-was-lib 찾기 + if (startPath != null) { + Path libSibling = startPath.resolveSibling("dat-was-lib"); + if (Files.isDirectory(libSibling)) { + return libSibling.resolve("src/main/resources/glow/application-glow-local.yml").normalize(); + } + } + + // 4. Fallback + if (sourceDir != null && !sourceDir.isBlank()) { + return Paths.get(sourceDir.trim()).resolve("dat-was-lib/src/main/resources/glow/application-glow-local.yml").normalize(); + } + return Paths.get("dat-was-lib/src/main/resources/glow/application-glow-local.yml").normalize(); + } + + private static Path ensureLocalHttpApiConfiguration(Path projectRoot, String httpApiName, String toolName) throws IOException { + Path localConfigPath = findGlowLocalConfigPath(projectRoot); Files.createDirectories(localConfigPath.getParent()); String existing = Files.exists(localConfigPath) ? Files.readString(localConfigPath, StandardCharsets.UTF_8) : ""; if (java.util.regex.Pattern.compile("(?m)^\\s*-\\s+name:\\s*" + java.util.regex.Pattern.quote(httpApiName) + "\\s*$").matcher(existing).find()) { - return; + return localConfigPath; } String environmentKey = toPackageSegment(httpApiName).toUpperCase(Locale.ROOT).replace('-', '_'); String apiEntry = """ @@ -1651,6 +2534,9 @@ public class ToolScaffolder { content-type: application/json;charset=UTF-8 biz-pod: false """.formatted(httpApiName, environmentKey, environmentKey, toolName).stripTrailing() + "\n"; + boolean isCrlf = existing.contains("\r\n"); + String formattedApiEntry = isCrlf ? apiEntry.replace("\n", "\r\n") : apiEntry; + if (existing.isBlank()) { existing = """ spring: @@ -1663,25 +2549,339 @@ public class ToolScaffolder { http: api-list: """ + apiEntry; + if (isCrlf) { + existing = existing.replace("\n", "\r\n"); + } + } else if (existing.contains("\r\n mci:")) { + existing = existing.replace("\r\n mci:", "\r\n" + formattedApiEntry + " mci:"); } else if (existing.contains("\n mci:")) { - existing = existing.replace("\n mci:", "\n" + apiEntry + " mci:"); + existing = existing.replace("\n mci:", "\n" + formattedApiEntry + " mci:"); + } else if (existing.contains("\r\naxhub:")) { + existing = existing.replace("\r\naxhub:", "\r\n" + formattedApiEntry + "axhub:"); } else if (existing.contains("\naxhub:")) { - existing = existing.replace("\naxhub:", apiEntry + "axhub:"); + existing = existing.replace("\naxhub:", "\n" + formattedApiEntry + "axhub:"); } else if (existing.contains("api-list:")) { - existing += apiEntry; + existing += formattedApiEntry; } else { throw new IllegalStateException("application-glow-local.yml must define glow.communication.http.api-list"); } - if (!existing.contains("axhub:\n mock:\n http:\n enabled: true")) { - existing += """ + if (!existing.contains("axhub:\n mock:\n http:\n enabled: true") + && !existing.contains("axhub:\r\n mock:\r\n http:\r\n enabled: true")) { + String mockConfig = """ axhub: mock: http: enabled: true """; + existing += isCrlf ? mockConfig.replace("\n", "\r\n") : mockConfig; } writeUtf8(localConfigPath, existing); + return localConfigPath; + } + + private static void writePagingComponents(Path pagingDir, String bizPackage, + String baseName, PagingMode pagingMode, + String ioPackage, String ioPrefix, + String clientClassName, String converterPkg, + String converterName, String interfaceId, + String receiveServiceId) throws IOException { + Files.createDirectories(pagingDir); + Path implDir = pagingDir.resolve("impl"); + Files.createDirectories(implDir); + + String pagingInfoType = pagingMode == PagingMode.SCROLL ? "ScrollPagingInfo" : "PgNumPagingInfo"; + String pagingSuffix = pagingMode == PagingMode.SCROLL ? "ScrollPaging" : "PageNumberPaging"; + String interfaceName = baseName + pagingSuffix; + String implName = interfaceName + "Impl"; + String clientImport = clientClassName.equals("AxhubMciComponent") + ? "import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;" + : "import " + ioPackage + "." + clientClassName + ";"; + + String interfaceSource = """ + package %s.paging; + + import %s.dto.%sRequest; + import %s.dto.%sResponse; + import io.shinhanlife.dat.lib.paging.MciPage; + import io.shinhanlife.dat.lib.paging.%s; + + /** + * @package %s.paging + * @className %s + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+                 * ---------- 개정이력 ----------
+                 * 수정일      수정자    수정내용
+                 * ---------- -------- ---------------------------
+                 * 2026.09.01  0986406    최초생성
+                 * 
+                 * 
+ */ + public interface %s { + + MciPage<%sResponse, %s> fetch(%sRequest request, %s pagingInfo); + } + """.formatted(bizPackage, bizPackage, baseName, bizPackage, baseName, pagingInfoType, + bizPackage, interfaceName, interfaceName, baseName, pagingInfoType, baseName, pagingInfoType); + writeUtf8(pagingDir.resolve(interfaceName + ".java"), interfaceSource); + + String implSource; + if (pagingMode == PagingMode.SCROLL) { + implSource = """ + package %s.paging.impl; + + import %s.dto.%sRequest; + import %s.dto.%sResponse; + import %s.paging.%s; + import %s.%s; + %s + import %s.io.%s_I; + import %s.io.%s_O; + import io.shinhanlife.dat.lib.paging.MciPage; + import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; + import io.shinhanlife.glow.db.dto.ScrPageInfo; + import io.shinhanlife.glow.communication.dto.Transfer; + import lombok.RequiredArgsConstructor; + import lombok.extern.slf4j.Slf4j; + import org.springframework.stereotype.Component; + + /** + * @package %s.paging.impl + * @className %s + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+                     * ---------- 개정이력 ----------
+                     * 수정일      수정자    수정내용
+                     * ---------- -------- ---------------------------
+                     * 2026.09.01  0986406    최초생성
+                     * 
+                     * 
+ */ + @Slf4j + @Component + @RequiredArgsConstructor + public class %s implements %s { + + private final %s mci; + private final %s converter; + + @Override + public MciPage<%sResponse, ScrollPagingInfo> fetch(%sRequest request, ScrollPagingInfo pagingInfo) { + if (request.getScrPageInfo() == null) { + request.setScrPageInfo(new ScrPageInfo()); + } + if (pagingInfo != null) { + if (pagingInfo.getScrlmhdNm() != null) request.getScrPageInfo().setScrlmhdNm(pagingInfo.getScrlmhdNm()); + if (pagingInfo.getScrlItva() != null) request.getScrPageInfo().setScrlItva(pagingInfo.getScrlItva()); + if (pagingInfo.getScrSortValu() != null) request.getScrPageInfo().setScrSortValu(pagingInfo.getScrSortValu()); + if (pagingInfo.getPageDataCc() > 0) request.getScrPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); + } + + %s_I mciReq = converter.toLegacyRequest(request); + if (mciReq != null && request.getScrPageInfo() != null) { + try { + java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", java.util.List.class); + setMethod.invoke(mciReq, java.util.List.of(request.getScrPageInfo())); + } catch (NoSuchMethodException e) { + try { + java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", ScrPageInfo.class); + setMethod.invoke(mciReq, request.getScrPageInfo()); + } catch (Exception ignored) {} + } catch (Exception ignored) {} + } + + Transfer<%s_O> resTransfer = mci.callTo("%s", "%s", mciReq, %s_O.class); + %s_O mciRes = resTransfer != null ? resTransfer.getBody() : null; + + %sResponse response = converter.toResponse(mciRes); + + ScrPageInfo resPageInfo = null; + if (mciRes != null) { + try { + java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getScrPageInfo"); + Object val = getMethod.invoke(mciRes); + if (val instanceof java.util.List list && !list.isEmpty()) { + if (list.get(0) instanceof ScrPageInfo pi) resPageInfo = pi; + } else if (val instanceof ScrPageInfo pi) { + resPageInfo = pi; + } + } catch (Exception ignored) {} + } + + boolean hasNext = resPageInfo != null && "Y".equalsIgnoreCase(resPageInfo.getNextDataExtYn()); + String nextSortValu = resPageInfo != null ? resPageInfo.getScrSortValu() : null; + String nextItva = resPageInfo != null ? resPageInfo.getScrlItva() : null; + + if (response != null) { + response.setHasMore(hasNext); + } + + ScrollPagingInfo nextPaging = new ScrollPagingInfo( + request.getScrPageInfo().getScrlmhdNm(), + nextItva, + nextSortValu, + hasNext, + request.getScrPageInfo().getPageDataCc() + ); + + return new MciPage<>(response, nextPaging); + } + } + """.formatted( + bizPackage, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, interfaceName, + converterPkg, converterName, + clientImport, + ioPackage, ioPrefix, + ioPackage, ioPrefix, + bizPackage, implName, + implName, interfaceName, + clientClassName, converterName, + baseName, baseName, + ioPrefix, + ioPrefix, interfaceId, receiveServiceId, ioPrefix, + ioPrefix, + baseName + ); + } else { + implSource = """ + package %s.paging.impl; + + import %s.dto.%sRequest; + import %s.dto.%sResponse; + import %s.paging.%s; + import %s.%s; + %s + import %s.io.%s_I; + import %s.io.%s_O; + import io.shinhanlife.dat.lib.paging.MciPage; + import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; + import io.shinhanlife.glow.db.dto.PageInfo; + import io.shinhanlife.glow.communication.dto.Transfer; + import lombok.RequiredArgsConstructor; + import lombok.extern.slf4j.Slf4j; + import org.springframework.stereotype.Component; + + /** + * @package %s.paging.impl + * @className %s + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+                     * ---------- 개정이력 ----------
+                     * 수정일      수정자    수정내용
+                     * ---------- -------- ---------------------------
+                     * 2026.09.01  0986406    최초생성
+                     * 
+                     * 
+ */ + @Slf4j + @Component + @RequiredArgsConstructor + public class %s implements %s { + + private final %s mci; + private final %s converter; + + @Override + public MciPage<%sResponse, PgNumPagingInfo> fetch(%sRequest request, PgNumPagingInfo pagingInfo) { + if (request.getPageInfo() == null) { + request.setPageInfo(new PageInfo()); + } + if (pagingInfo != null) { + if (pagingInfo.getPageNo() > 0) request.getPageInfo().setPageNo(pagingInfo.getPageNo()); + if (pagingInfo.getPageDataCc() > 0) request.getPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); + } + + %s_I mciReq = converter.toLegacyRequest(request); + if (mciReq != null) { + try { + java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", java.util.List.class); + setMethod.invoke(mciReq, java.util.List.of(request.getPageInfo())); + } catch (NoSuchMethodException e) { + try { + java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", PageInfo.class); + setMethod.invoke(mciReq, request.getPageInfo()); + } catch (Exception ignored) {} + } catch (Exception ignored) {} + } + + Transfer<%s_O> resTransfer = mci.callTo("%s", "%s", mciReq, %s_O.class); + %s_O mciRes = resTransfer != null ? resTransfer.getBody() : null; + + %sResponse response = converter.toResponse(mciRes); + + PageInfo resPageInfo = null; + if (mciRes != null) { + try { + java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getPageInfo"); + Object val = getMethod.invoke(mciRes); + if (val instanceof java.util.List list && !list.isEmpty()) { + if (list.get(0) instanceof PageInfo pi) resPageInfo = pi; + } else if (val instanceof PageInfo pi) { + resPageInfo = pi; + } + } catch (Exception ignored) {} + } + + int currentPageNo = resPageInfo != null && resPageInfo.getPageNo() > 0 ? resPageInfo.getPageNo() : (pagingInfo != null ? pagingInfo.getPageNo() : 1); + int totalPageCn = resPageInfo != null ? resPageInfo.getTotaPageCn() : 0; + int totalDataCc = resPageInfo != null ? resPageInfo.getTotaPageDataCc() : 0; + int pageDataCc = resPageInfo != null && resPageInfo.getPageDataCc() > 0 ? resPageInfo.getPageDataCc() : (pagingInfo != null ? pagingInfo.getPageDataCc() : 20); + + boolean hasNext = false; + if (totalPageCn > 0) { + hasNext = currentPageNo < totalPageCn; + } else if (totalDataCc > 0 && pageDataCc > 0) { + hasNext = (long) currentPageNo * pageDataCc < totalDataCc; + } + + if (response != null) { + response.setPageNo(currentPageNo); + response.setTotalPageCount(totalPageCn); + response.setTotalCount(totalDataCc); + response.setHasMore(hasNext); + } + + PgNumPagingInfo nextPaging = new PgNumPagingInfo( + currentPageNo + 1, + pageDataCc, + totalPageCn, + totalDataCc, + hasNext + ); + + return new MciPage<>(response, nextPaging); + } + } + """.formatted( + bizPackage, + bizPackage, baseName, + bizPackage, baseName, + bizPackage, interfaceName, + converterPkg, converterName, + clientImport, + ioPackage, ioPrefix, + ioPackage, ioPrefix, + bizPackage, implName, + implName, interfaceName, + clientClassName, converterName, + baseName, baseName, + ioPrefix, + ioPrefix, interfaceId, receiveServiceId, ioPrefix, + ioPrefix, + baseName + ); + } + writeUtf8(implDir.resolve(implName + ".java"), implSource); } private static void writeUtf8(Path path, String content) throws IOException { @@ -1690,42 +2890,125 @@ public class ToolScaffolder { private static String dtoContent(String packageName, String className, List fields, String author, String createDate, boolean request) { - String body = fieldLines(fields, request ? Set.of() : Set.of("resultCode", "resultMessage"), className); + return dtoContent(packageName, className, fields, author, createDate, request, PagingMode.NONE); + } + + private static String dtoContent(String packageName, String className, List fields, + String author, String createDate, boolean request, PagingMode pagingMode) { + Set excludedFields; + if (request) { + if (pagingMode == PagingMode.PAGE_NUMBER) { + excludedFields = Set.of("pageInfo"); + } else if (pagingMode == PagingMode.SCROLL) { + excludedFields = Set.of("scrPageInfo"); + } else { + excludedFields = Set.of(); + } + } else { + if (pagingMode == PagingMode.PAGE_NUMBER) { + excludedFields = Set.of("resultCode", "resultMessage", "pageNo", "totalPageCount", "totalCount", "hasMore"); + } else if (pagingMode == PagingMode.SCROLL) { + excludedFields = Set.of("resultCode", "resultMessage", "hasMore"); + } else { + excludedFields = Set.of("resultCode", "resultMessage"); + } + } + String body = fieldLines(fields, excludedFields, className); if (!request) { - body = " private String resultCode;\n\n private String resultMessage;\n" + body; + String pagingResponseFields = ""; + if (pagingMode == PagingMode.PAGE_NUMBER) { + pagingResponseFields = """ + @Schema(description = "현재 페이지 번호") + private Integer pageNo; + + @Schema(description = "총 페이지 수") + private Integer totalPageCount; + + @Schema(description = "총 데이터 건수") + private Integer totalCount; + + @Schema(description = "추가 데이터 존재 여부 (기본 최대 조회 건수 초과 시 true)") + private Boolean hasMore; + + """; + } else if (pagingMode == PagingMode.SCROLL) { + pagingResponseFields = """ + @Schema(description = "추가 데이터 존재 여부 (기본 최대 조회 건수 초과 시 true)") + private Boolean hasMore; + + """; + } + body = " private String resultCode;\n\n private String resultMessage;\n\n" + pagingResponseFields + body; } String listImport = hasListField(fields) ? "import java.util.List;\n" : ""; String patternImport = hasPatternField(fields) ? "import jakarta.validation.constraints.Pattern;\n" : ""; + String pagingImport = ""; + String pagingField = ""; + if (request && pagingMode != null && pagingMode != PagingMode.NONE) { + if (pagingMode == PagingMode.PAGE_NUMBER) { + pagingImport = "import io.shinhanlife.glow.db.dto.PageInfo;\n"; + pagingField = " @Schema(description = \"페이지 정보\")\n private PageInfo pageInfo;\n\n"; + } else if (pagingMode == PagingMode.SCROLL) { + pagingImport = "import io.shinhanlife.glow.db.dto.ScrPageInfo;\n"; + pagingField = " @Schema(description = \"스크롤 페이지 정보\")\n private ScrPageInfo scrPageInfo;\n\n"; + } + } return """ package %s; import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; - %s%s - + %s%s%s @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class %s { - %s%s} - """.formatted(packageName, listImport, patternImport, className, body, innerObjectListClasses(fields)); + %s%s%s} + """.formatted(packageName, listImport, patternImport, pagingImport, className, pagingField, body, innerObjectListClasses(fields)); } private static String mciIoContent(String packageSuffix, String className, List fields, String author, String createDate) { + return mciIoContent(packageSuffix, className, fields, author, createDate, PagingMode.NONE); + } + + private static String mciIoContent(String packageSuffix, String className, List fields, + String author, String createDate, PagingMode pagingMode) { String listImport = hasListField(fields) ? "import java.util.List;\n" : ""; String patternImport = hasPatternField(fields) ? "import jakarta.validation.constraints.Pattern;\n" : ""; + String pagingImport = ""; + String pagingField = ""; + Set excluded = Set.of(); + if ((className.endsWith("_I") || className.endsWith("_O")) && pagingMode != null && pagingMode != PagingMode.NONE) { + boolean hasPageInfo = fields != null && fields.stream().anyMatch(f -> f != null && "pageInfo".equalsIgnoreCase(f.name())); + boolean hasScrPageInfo = fields != null && fields.stream().anyMatch(f -> f != null && "scrPageInfo".equalsIgnoreCase(f.name())); + if (pagingMode == PagingMode.PAGE_NUMBER) { + excluded = Set.of("pageInfo"); + if (!hasPageInfo) { + pagingImport = "import io.shinhanlife.glow.GlowTrgmField;\nimport io.shinhanlife.glow.db.dto.PageInfo;\n"; + if (!listImport.contains("List")) { + pagingImport += "import java.util.List;\n"; + } + pagingField = " @Schema(description = \"페이지 정보\")\n @GlowTrgmField(order = 1, description = \"페이지 정보\", type = \"gm\")\n private List pageInfo;\n\n"; + } + } else if (pagingMode == PagingMode.SCROLL) { + excluded = Set.of("scrPageInfo"); + if (!hasScrPageInfo) { + pagingImport = "import io.shinhanlife.glow.GlowTrgmField;\nimport io.shinhanlife.glow.db.dto.ScrPageInfo;\n"; + pagingField = " @Schema(description = \"스크롤 페이지 정보\")\n @GlowTrgmField(order = 1, length = 306, description = \"스크롤 페이지 정보\")\n private ScrPageInfo scrPageInfo;\n\n"; + } + } + } return """ package %s.%s.io; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; - %s%s - + %s%s%s @Data public class %s { - %s%s} - """.formatted(BASE_PACKAGE, packageSuffix, listImport, patternImport, className, fieldLines(fields, Set.of(), className), + %s%s%s} + """.formatted(BASE_PACKAGE, packageSuffix, listImport, patternImport, pagingImport, className, pagingField, fieldLines(fields, excluded, className), innerObjectListClasses(fields)); } @@ -1834,7 +3117,8 @@ public class ToolScaffolder { String httpResponseClass = baseName + "HttpResponse"; String httpClientClass = httpApiClass + "Client"; String clientVariable = Character.toLowerCase(httpClientClass.charAt(0)) + httpClientClass.substring(1); - return """ + String methodName = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1); + String result = """ package %s.usecase.impl; import %s.converter.%sConverter; @@ -1879,6 +3163,7 @@ public class ToolScaffolder { baseName, baseName, httpRequestClass, httpResponseClass, clientVariable, httpResponseClass, baseName); + return result.replace("execute(", methodName + "("); } private static String httpClientContent(String httpPackage, String clientClass, String apiName) { @@ -1936,9 +3221,10 @@ public class ToolScaffolder { .replaceAll("^_+|_+$", ""); return normalized.isBlank() ? "http_api" : normalized; } - private static String mciConverterContent(String bizPackage, String baseName, String mciPackage, String interfaceId) { + private static String mciConverterContent(String converterPackage, String bizPackage, String baseName, + String mciPackage, String interfaceId, String converterClassName) { return """ - package %s.converter; + package %s; import %s.dto.%sRequest; import %s.dto.%sResponse; @@ -1949,16 +3235,27 @@ public class ToolScaffolder { import org.mapstruct.ReportingPolicy; @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) - public interface %sConverter { + public interface %s { // Field names differ? Add mappings like this before the method. // @Mapping(source = "sourceField", target = "targetField") %s_I toLegacyRequest(%sRequest request); + default %s_I toRequest(%sRequest request) { + return toLegacyRequest(request); + } %sRequest toRequest(%s_I mciRequest); %sResponse toResponse(%s_O mciRes); } - """.formatted(bizPackage, bizPackage, baseName, bizPackage, baseName, + """.formatted(converterPackage, bizPackage, baseName, bizPackage, baseName, BASE_PACKAGE, mciPackage, interfaceId, BASE_PACKAGE, mciPackage, interfaceId, - baseName, interfaceId, baseName, baseName, interfaceId, baseName, interfaceId); + converterClassName, interfaceId, baseName, interfaceId, baseName, baseName, interfaceId, baseName, interfaceId); + } + + private static String mciTargetSystemPackage(String clientSystemCode) { + if (clientSystemCode == null || clientSystemCode.length() != 9) { + return null; + } + String prefix = clientSystemCode.substring(1, 5).toLowerCase(Locale.ROOT); + return prefix.substring(0, 3) + "." + prefix.substring(3); } private static String legacyConverterContent(String bizPackage, String baseName) { @@ -2006,10 +3303,10 @@ public class ToolScaffolder { continue; } String type = javaFieldType(field, ownerClass); - String description = richDescription(field).replace("\"", "\\\""); + String description = javaText(richDescription(field)); String example = ""; if (field.examples() != null && !field.examples().isEmpty()) { - example = field.examples().get(0).replace("\"", "\\\""); + example = javaText(field.examples().get(0)); } source.append(" @Schema(description = \"").append(description).append("\""); if (!example.isEmpty()) { @@ -2020,7 +3317,7 @@ public class ToolScaffolder { } source.append(")\n"); if (field.pattern() != null && !field.pattern().isBlank()) { - source.append(" @Pattern(regexp = \"").append(field.pattern().replace("\"", "\\\"")).append("\")\n"); + source.append(" @Pattern(regexp = \"").append(javaText(field.pattern())).append("\")\n"); } source.append(" private ").append(type).append(' ').append(fieldName).append(";\n\n"); } @@ -2032,9 +3329,6 @@ public class ToolScaffolder { if (field.pattern() != null && !field.pattern().isBlank()) { desc += " (형식: " + field.pattern() + ")"; } - if (field.examples() != null && !field.examples().isEmpty()) { - desc += " (예시: " + String.join(", ", field.examples()) + ")"; - } return desc.trim(); } @@ -2163,19 +3457,23 @@ public class ToolScaffolder { action); } + private static String abbreviatedMciSourceBaseName(String baseName) { + String[] words = baseName.split("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])"); + if (words.length < 3) { + return baseName; + } + return abbreviatedWord(words[0], 4) + abbreviatedWord(words[1], 6); + } + + private static String abbreviatedWord(String word, int maximumLength) { + int length = Math.min(word.length(), maximumLength); + return toPascalCase(word.substring(0, length).toLowerCase(Locale.ROOT)); + } + private static String toPascalCase(String str) { if (str == null || str.isEmpty()) { return str; } - - boolean hasLowercase = false; - for (char c : str.toCharArray()) { - if (Character.isLowerCase(c)) { - hasLowercase = true; - break; - } - } - StringBuilder result = new StringBuilder(); boolean capitalizeNext = true; for (char c : str.toCharArray()) { @@ -2185,7 +3483,7 @@ public class ToolScaffolder { result.append(Character.toUpperCase(c)); capitalizeNext = false; } else { - result.append(hasLowercase ? c : Character.toLowerCase(c)); + result.append(c); } } if (result.length() > 0) { diff --git a/dat-was-lib/src/main/resources/codes.csv b/dat-was-lib/src/main/resources/codes.csv new file mode 100644 index 000000000..f268bc248 --- /dev/null +++ b/dat-was-lib/src/main/resources/codes.csv @@ -0,0 +1,17 @@ +그룹,코드,명칭 +COMPANY,005930,삼성전자 +COMPANY,035420,NAVER +COMPANY,035720,카카오 +COMPANY,000660,SK하이닉스 +COMPANY,055550,신한지주 +COMPANY,086790,하나금융지주 +COMPANY,105560,KB금융 +COMPANY,316140,우리금융지주 +COMPANY,000810,삼성화재 +COMPANY,088350,한화생명 +COMPANY,005830,DB손해보험 +COMPANY,000030,우리은행 +STATUS,01,정상 +STATUS,02,비정상 +STATUS,03,해지 +STATUS,04,실효 \ No newline at end of file diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/CommonCodeResolverTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/CommonCodeResolverTest.java new file mode 100644 index 000000000..f16cbd45e --- /dev/null +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/CommonCodeResolverTest.java @@ -0,0 +1,62 @@ +package io.shinhanlife.dat.lib.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** + * @package io.shinhanlife.dat.lib.util + * @className CommonCodeResolverTest + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ +class CommonCodeResolverTest { + + @Test + void resolvesCompanyCodeFromExactName() { + assertEquals("005930", CommonCodeResolver.resolve("COMPANY", "삼성전자")); + assertEquals("035420", CommonCodeResolver.resolve("COMPANY", "NAVER")); + assertEquals("035720", CommonCodeResolver.resolve("COMPANY", "카카오")); + assertEquals("055550", CommonCodeResolver.resolve("COMPANY", "신한지주")); + } + + @Test + void resolvesCompanyCodeWhenAlreadyCode() { + assertEquals("005930", CommonCodeResolver.resolve("COMPANY", "005930")); + assertEquals("035420", CommonCodeResolver.resolve("COMPANY", "035420")); + } + + @Test + void resolvesCaseInsensitiveAndSpaceIgnored() { + assertEquals("035420", CommonCodeResolver.resolve("COMPANY", "naver")); + assertEquals("005930", CommonCodeResolver.resolve("COMPANY", "삼성 전자")); + } + + @Test + void resolvesStatusGroupCode() { + assertEquals("01", CommonCodeResolver.resolve("STATUS", "정상")); + assertEquals("02", CommonCodeResolver.resolve("STATUS", "비정상")); + assertEquals("03", CommonCodeResolver.resolve("STATUS", "해지")); + assertEquals("01", CommonCodeResolver.resolve("STATUS", "01")); + } + + @Test + void getsNameFromCode() { + assertEquals("삼성전자", CommonCodeResolver.getName("COMPANY", "005930")); + assertEquals("정상", CommonCodeResolver.getName("STATUS", "01")); + } + + @Test + void returnsOriginalWhenNotFound() { + assertEquals("알수없는회사", CommonCodeResolver.resolve("COMPANY", "알수없는회사")); + assertEquals("99", CommonCodeResolver.resolve("STATUS", "99")); + } +} \ No newline at end of file diff --git a/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverter.java b/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverter.java index 2866e8598..c5b0c1f8b 100644 --- a/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverter.java +++ b/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverter.java @@ -1,5 +1,6 @@ package io.shinhanlife.dat.mcc.biz.pro.converter; +import io.shinhanlife.dat.lib.util.CommonCodeResolver; import io.shinhanlife.dat.mcc.biz.pro.dto.RecruitmentFeeDisclosureDataRequest; import io.shinhanlife.dat.mcc.biz.pro.dto.RecruitmentFeeDisclosureDataResponse; import io.shinhanlife.dat.mcc.infra.itrf.mci.nbt.i.io.ONBTI2370_I; @@ -8,11 +9,30 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; +/** + * @package io.shinhanlife.dat.mcc.biz.pro.converter + * @className RecruitmentFeeDisclosureDataConverter + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface RecruitmentFeeDisclosureDataConverter { - // Field names differ? Add mappings like this before the method. - // @Mapping(source = "sourceField", target = "targetField") + + @Mapping(target = "companyCode", expression = "java(toCompanyCode(request.getCompanyCode()))") ONBTI2370_I toLegacyRequest(RecruitmentFeeDisclosureDataRequest request); + + default String toCompanyCode(String company) { + return CommonCodeResolver.resolve("COMPANY", company); + } + RecruitmentFeeDisclosureDataRequest toRequest(ONBTI2370_I mciRequest); RecruitmentFeeDisclosureDataResponse toResponse(ONBTI2370_O mciRes); } diff --git a/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/dto/RecruitmentFeeDisclosureDataRequest.java b/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/dto/RecruitmentFeeDisclosureDataRequest.java index f445b1098..fd8c633ac 100644 --- a/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/dto/RecruitmentFeeDisclosureDataRequest.java +++ b/dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro/dto/RecruitmentFeeDisclosureDataRequest.java @@ -6,11 +6,24 @@ import lombok.Data; import jakarta.validation.constraints.Pattern; +/** + * @package io.shinhanlife.dat.mcc.biz.pro.dto + * @className RecruitmentFeeDisclosureDataRequest + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class RecruitmentFeeDisclosureDataRequest { - @Schema(description = "조회할 회사의 코드 (형식: ^[0-9]{6}$) (예시: 005930, 035420)", example = "005930", requiredMode = Schema.RequiredMode.REQUIRED) - @Pattern(regexp = "^[0-9]{6}$") + @Schema(description = "조회할 회사 코드 또는 회사명 (예시: 005930, 삼성전자, NAVER, 카카오)", example = "삼성전자", requiredMode = Schema.RequiredMode.REQUIRED) private String companyCode; @Schema(description = "조회할 연도 (형식: ^[0-9]{4}$) (예시: 2023, 2024)", example = "2023", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/dat-was-pro/src/test/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverterTest.java b/dat-was-pro/src/test/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverterTest.java new file mode 100644 index 000000000..09d94c701 --- /dev/null +++ b/dat-was-pro/src/test/java/io/shinhanlife/dat/mcc/biz/pro/converter/RecruitmentFeeDisclosureDataConverterTest.java @@ -0,0 +1,67 @@ +package io.shinhanlife.dat.mcc.biz.pro.converter; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.shinhanlife.dat.mcc.biz.pro.dto.RecruitmentFeeDisclosureDataRequest; +import io.shinhanlife.dat.mcc.infra.itrf.mci.nbt.i.io.ONBTI2370_I; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +/** + * @package io.shinhanlife.dat.mcc.biz.pro.converter + * @className RecruitmentFeeDisclosureDataConverterTest + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ +class RecruitmentFeeDisclosureDataConverterTest { + + private final RecruitmentFeeDisclosureDataConverter converter = + Mappers.getMapper(RecruitmentFeeDisclosureDataConverter.class); + + @Test + void mapsCompanyNameToLegacyCompanyCode() { + RecruitmentFeeDisclosureDataRequest request = new RecruitmentFeeDisclosureDataRequest(); + request.setCompanyCode("삼성전자"); + request.setYear("2024"); + request.setQuarter("1"); + + ONBTI2370_I legacyReq = converter.toLegacyRequest(request); + + assertNotNull(legacyReq); + assertEquals("005930", legacyReq.getCompanyCode()); + assertEquals("2024", legacyReq.getYear()); + assertEquals("1", legacyReq.getQuarter()); + } + + @Test + void preservesCompanyCodeWhenAlreadyNumericCode() { + RecruitmentFeeDisclosureDataRequest request = new RecruitmentFeeDisclosureDataRequest(); + request.setCompanyCode("035420"); + request.setYear("2024"); + + ONBTI2370_I legacyReq = converter.toLegacyRequest(request); + + assertNotNull(legacyReq); + assertEquals("035420", legacyReq.getCompanyCode()); + } + + @Test + void mapsNaverAndKakao() { + RecruitmentFeeDisclosureDataRequest requestNaver = new RecruitmentFeeDisclosureDataRequest(); + requestNaver.setCompanyCode("NAVER"); + assertEquals("035420", converter.toLegacyRequest(requestNaver).getCompanyCode()); + + RecruitmentFeeDisclosureDataRequest requestKakao = new RecruitmentFeeDisclosureDataRequest(); + requestKakao.setCompanyCode("카카오"); + assertEquals("035720", converter.toLegacyRequest(requestKakao).getCompanyCode()); + } +} \ No newline at end of file From 5f58c22efef3f5c58374e0ecb8663b9f0ae41f2d Mon Sep 17 00:00:00 2001 From: jade Date: Thu, 17 Sep 2026 10:22:25 +0900 Subject: [PATCH 3/3] feat: extract MciPagingUtils and update ToolScaffolder --- .../dat/lib/paging/MciPagingUtils.java | 69 ++++++ .../dat/lib/util/ToolScaffolder.java | 233 ++++++------------ 2 files changed, 142 insertions(+), 160 deletions(-) create mode 100644 dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java new file mode 100644 index 000000000..fe8cdf0d9 --- /dev/null +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java @@ -0,0 +1,69 @@ +package io.shinhanlife.dat.lib.paging; + +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * @package io.shinhanlife.dat.lib.paging + * @className MciPagingUtils + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ +@Slf4j +public final class MciPagingUtils { + + private MciPagingUtils() { + } + + /** + * 페이징 응답 데이터(List 필드)를 대상(target) 객체에 순차적으로 병합(append)합니다. + * 클래스 상속 계층 구조를 탐색하여 모든 List 타입 필드를 병합합니다. + * + * @param target 누적할 최종 응답 DTO + * @param src 각 페이지별 응답 DTO + */ + public static void mergeResponseData(Object target, Object src) { + if (target == null || src == null) { + return; + } + Class current = target.getClass(); + while (current != null && current != Object.class) { + for (Field field : current.getDeclaredFields()) { + if (List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + List srcList = (List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + List targetList = (List) field.get(target); + if (targetList == null) { + targetList = new ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof ArrayList)) { + targetList = new ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + current = current.getSuperclass(); + } + } +} diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java index 680acaafc..a772c9ec6 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java @@ -119,17 +119,6 @@ public class ToolScaffolder { } } - public static String businessProposalGuide() { - return """ - [업무 제안서 작성 가이드] - 통합계약원부 조회 - 1. 조회 대상·식별 기준: 무엇을 어떤 값으로 찾는지 - 계약번호가 있으면 상세 원부를 조회 - 2. 조회 목적·사용처: 어떤 업무 상황에서 쓰는지 - 해지·대출·보험금 상세는 별도 Tool - """; - } - public static String scaffoldUseCase(String useCaseName, String moduleName, String author, String createDate, List tools) throws IOException { if (tools == null || tools.isEmpty()) { @@ -340,7 +329,7 @@ public class ToolScaffolder { ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" : baseName + "Converter"; writeUtf8(targetConverterDir.resolve(converterName + ".java"), - groupedMciConverterContent(converterPkg, bizPackage, baseName, ioPackage, ioPrefix, converterName)); + groupedMciConverterContent(converterPkg, bizPackage, baseName, ioPackage, ioPrefix, converterName, pagingMode)); } else { writeUtf8(ioDir.resolve(baseName + "HttpRequest.java"), dtoContent(ioPackage + ".io", baseName + "HttpRequest", tool.inputFields(), "", "", true)); @@ -440,7 +429,8 @@ public class ToolScaffolder { .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n") .append("import ").append(bizPackage).append(".paging.").append(pagingInterface).append(";\n") .append("import io.shinhanlife.dat.lib.paging.MciPage;\n") - .append("import io.shinhanlife.dat.lib.paging.").append(pagingInfoType).append(";\n"); + .append("import io.shinhanlife.dat.lib.paging.").append(pagingInfoType).append(";\n") + .append("import io.shinhanlife.dat.lib.paging.MciPagingUtils;\n"); if (!fields.toString().contains(" " + pagingVar + ";")) { fields.append(" private final ").append(pagingInterface).append(" ").append(pagingVar).append(";\n"); @@ -488,39 +478,7 @@ public class ToolScaffolder { if (hasMciOrPaging) { imports.append("import lombok.extern.slf4j.Slf4j;\n"); } - boolean hasPaging = tools.stream().anyMatch(t -> t.definitionOptions() != null && t.definitionOptions().pagingModeOrNone() != PagingMode.NONE); - if (hasPaging) { - methods.append(""" - private void mergeResponseData(Object target, Object src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } - """); - } return "package " + bizPackage + ".usecase.impl;\n\n" + "import " + bizPackage + ".usecase." + useCaseBaseName + "UseCase;\n" + "import lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\n" + imports @@ -538,7 +496,7 @@ public class ToolScaffolder { @Override public %sResponse %s(%sRequest req) { - log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); try { %s pagingInfo = null; %s pagingInfoLast = null; @@ -554,7 +512,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -566,8 +524,18 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = new %sResponse(); + finalResponse.setResultCode("FAIL"); + finalResponse.setResultMessage("MCI 응답 데이터가 존재하지 않습니다."); + finalResponse.setHasMore(false); + finalResponse.setPageNo(1); + finalResponse.setTotalPageCount(0); + finalResponse.setTotalCount(0); + return finalResponse; + } + + if (finalResponse.getResultCode() == null || finalResponse.getResultCode().isBlank()) { + finalResponse.setResultCode("SUCCESS"); } - finalResponse.setResultCode("SUCCESS"); finalResponse.setHasMore(hasMore); if (pagingInfoLast != null) { int lastPageNo = Math.max(1, pagingInfoLast.getPageNo() - 1); @@ -598,7 +566,7 @@ public class ToolScaffolder { } """.formatted( baseName, tool.methodName(), baseName, - pagingMode, snakeToolName, pagingMode, + snakeToolName, pagingMode, pagingInfoType, pagingInfoType, baseName, @@ -610,7 +578,7 @@ public class ToolScaffolder { @Override public %sResponse %s(%sRequest req) { - log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); try { %s pagingInfo = null; %sResponse finalResponse = null; @@ -624,7 +592,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -636,8 +604,15 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = new %sResponse(); + finalResponse.setResultCode("FAIL"); + finalResponse.setResultMessage("MCI 응답 데이터가 존재하지 않습니다."); + finalResponse.setHasMore(false); + return finalResponse; + } + + if (finalResponse.getResultCode() == null || finalResponse.getResultCode().isBlank()) { + finalResponse.setResultCode("SUCCESS"); } - finalResponse.setResultCode("SUCCESS"); finalResponse.setHasMore(hasMore); if (hasMore) { finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (총 " + loopCount + "회 호출, hasMore=true)."); @@ -656,7 +631,7 @@ public class ToolScaffolder { } """.formatted( baseName, tool.methodName(), baseName, - pagingMode, snakeToolName, pagingMode, + snakeToolName, pagingMode, pagingInfoType, baseName, baseName, pagingInfoType, pagingVariable, @@ -729,16 +704,26 @@ public class ToolScaffolder { + "public interface " + useCaseBaseName + "Converter {\n}\n"; } - private static String groupedMciConverterContent(String converterPackage, String bizPackage, String baseName, String ioPackage, String interfaceId, String converterName) { + private static String groupedMciConverterContent(String converterPackage, String bizPackage, String baseName, String ioPackage, String interfaceId, String converterName, PagingMode pagingMode) { + String pageIgnore = ""; + if (pagingMode == PagingMode.PAGE_NUMBER) { + pageIgnore = " @Mapping(target = \"pageInfo\", ignore = true)\n"; + } else if (pagingMode == PagingMode.SCROLL) { + pageIgnore = " @Mapping(target = \"scrPageInfo\", ignore = true)\n"; + } return "package " + converterPackage + ";\n\n" + "import " + bizPackage + ".dto." + baseName + "Request;\n" + "import " + bizPackage + ".dto." + baseName + "Response;\n" + "import " + ioPackage + ".io." + interfaceId + "_I;\n" + "import " + ioPackage + ".io." + interfaceId + "_O;\n" - + "import org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n\n" + + "import org.mapstruct.Mapper;\nimport org.mapstruct.Mapping;\nimport org.mapstruct.ReportingPolicy;\n\n" + "@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n" + "public interface " + converterName + " {\n" - + " " + interfaceId + "_I toRequest(" + baseName + "Request request);\n" + + pageIgnore + + " " + interfaceId + "_I toRequest(" + baseName + "Request request);\n\n" + + " default " + interfaceId + "_I toLegacyRequest(" + baseName + "Request request) {\n" + + " return toRequest(request);\n" + + " }\n\n" + " " + baseName + "Response toResponse(" + interfaceId + "_O response);\n}\n"; } @@ -844,6 +829,7 @@ public class ToolScaffolder { implementation = addImport(implementation, "import " + bizPackage + ".paging." + pagingInterface + ";"); implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging.MciPage;"); implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging." + pagingInfoType + ";"); + implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging.MciPagingUtils;"); implementation = addImport(implementation, "import lombok.extern.slf4j.Slf4j;"); if (!implementation.contains("@Slf4j")) { implementation = implementation.replaceFirst("public class ", "@Slf4j\npublic class "); @@ -857,38 +843,6 @@ public class ToolScaffolder { } String method = groupedToolPagingMethodContent(tool, baseName, pagingVar, pagingMode, pagingInfoType); implementation = insertBeforeLastBrace(implementation, method); - if (!implementation.contains("mergeResponseData(")) { - implementation = insertBeforeLastBrace(implementation, """ - - private void mergeResponseData(Object target, Object src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } - """); - } } else { String clientClassName; String clientVariable; @@ -1381,6 +1335,7 @@ public class ToolScaffolder { import %s.paging.%s; import io.shinhanlife.dat.lib.paging.MciPage; import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; + import io.shinhanlife.dat.lib.paging.MciPagingUtils; import io.shinhanlife.glow.BizException; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -1425,7 +1380,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -1477,34 +1432,6 @@ public class ToolScaffolder { return response; } } - - private void mergeResponseData(%sResponse target, %sResponse src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } } """.formatted( bizPackage, @@ -1525,7 +1452,6 @@ public class ToolScaffolder { baseName, baseName, baseName, baseName, - baseName, baseName, baseName, baseName ); } else { @@ -1538,6 +1464,7 @@ public class ToolScaffolder { import %s.paging.%s; import io.shinhanlife.dat.lib.paging.MciPage; import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; + import io.shinhanlife.dat.lib.paging.MciPagingUtils; import io.shinhanlife.glow.BizException; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -1580,7 +1507,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -1617,34 +1544,6 @@ public class ToolScaffolder { return response; } } - - private void mergeResponseData(%sResponse target, %sResponse src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } } """.formatted( bizPackage, @@ -1665,7 +1564,6 @@ public class ToolScaffolder { baseName, baseName, baseName, baseName, - baseName, baseName, baseName, baseName ); } @@ -2644,6 +2542,8 @@ public class ToolScaffolder { import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; import io.shinhanlife.glow.db.dto.ScrPageInfo; import io.shinhanlife.glow.communication.dto.Transfer; + import java.lang.reflect.Method; + import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -2675,6 +2575,9 @@ public class ToolScaffolder { if (request.getScrPageInfo() == null) { request.setScrPageInfo(new ScrPageInfo()); } + if (request.getScrPageInfo().getPageDataCc() <= 0) { + request.getScrPageInfo().setPageDataCc(20); + } if (pagingInfo != null) { if (pagingInfo.getScrlmhdNm() != null) request.getScrPageInfo().setScrlmhdNm(pagingInfo.getScrlmhdNm()); if (pagingInfo.getScrlItva() != null) request.getScrPageInfo().setScrlItva(pagingInfo.getScrlItva()); @@ -2682,14 +2585,14 @@ public class ToolScaffolder { if (pagingInfo.getPageDataCc() > 0) request.getScrPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); } - %s_I mciReq = converter.toLegacyRequest(request); + %s_I mciReq = converter.toRequest(request); if (mciReq != null && request.getScrPageInfo() != null) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", java.util.List.class); - setMethod.invoke(mciReq, java.util.List.of(request.getScrPageInfo())); + Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", List.class); + setMethod.invoke(mciReq, List.of(request.getScrPageInfo())); } catch (NoSuchMethodException e) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", ScrPageInfo.class); + Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", ScrPageInfo.class); setMethod.invoke(mciReq, request.getScrPageInfo()); } catch (Exception ignored) {} } catch (Exception ignored) {} @@ -2703,9 +2606,9 @@ public class ToolScaffolder { ScrPageInfo resPageInfo = null; if (mciRes != null) { try { - java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getScrPageInfo"); + Method getMethod = mciRes.getClass().getMethod("getScrPageInfo"); Object val = getMethod.invoke(mciRes); - if (val instanceof java.util.List list && !list.isEmpty()) { + if (val instanceof List list && !list.isEmpty()) { if (list.get(0) instanceof ScrPageInfo pi) resPageInfo = pi; } else if (val instanceof ScrPageInfo pi) { resPageInfo = pi; @@ -2765,6 +2668,8 @@ public class ToolScaffolder { import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; import io.shinhanlife.glow.db.dto.PageInfo; import io.shinhanlife.glow.communication.dto.Transfer; + import java.lang.reflect.Method; + import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -2796,19 +2701,25 @@ public class ToolScaffolder { if (request.getPageInfo() == null) { request.setPageInfo(new PageInfo()); } + if (request.getPageInfo().getPageNo() <= 0) { + request.getPageInfo().setPageNo(1); + } + if (request.getPageInfo().getPageDataCc() <= 0) { + request.getPageInfo().setPageDataCc(20); + } if (pagingInfo != null) { if (pagingInfo.getPageNo() > 0) request.getPageInfo().setPageNo(pagingInfo.getPageNo()); if (pagingInfo.getPageDataCc() > 0) request.getPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); } - %s_I mciReq = converter.toLegacyRequest(request); + %s_I mciReq = converter.toRequest(request); if (mciReq != null) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", java.util.List.class); - setMethod.invoke(mciReq, java.util.List.of(request.getPageInfo())); + Method setMethod = mciReq.getClass().getMethod("setPageInfo", List.class); + setMethod.invoke(mciReq, List.of(request.getPageInfo())); } catch (NoSuchMethodException e) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", PageInfo.class); + Method setMethod = mciReq.getClass().getMethod("setPageInfo", PageInfo.class); setMethod.invoke(mciReq, request.getPageInfo()); } catch (Exception ignored) {} } catch (Exception ignored) {} @@ -2822,9 +2733,9 @@ public class ToolScaffolder { PageInfo resPageInfo = null; if (mciRes != null) { try { - java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getPageInfo"); + Method getMethod = mciRes.getClass().getMethod("getPageInfo"); Object val = getMethod.invoke(mciRes); - if (val instanceof java.util.List list && !list.isEmpty()) { + if (val instanceof List list && !list.isEmpty()) { if (list.get(0) instanceof PageInfo pi) resPageInfo = pi; } else if (val instanceof PageInfo pi) { resPageInfo = pi; @@ -3238,6 +3149,8 @@ public class ToolScaffolder { public interface %s { // Field names differ? Add mappings like this before the method. // @Mapping(source = "sourceField", target = "targetField") + @Mapping(target = "pageInfo", ignore = true) + @Mapping(target = "scrPageInfo", ignore = true) %s_I toLegacyRequest(%sRequest request); default %s_I toRequest(%sRequest request) { return toLegacyRequest(request);