feat: update MCP contracts and integrations
All checks were successful
Deploy Tools / deploy (push) Successful in 1m34s

This commit is contained in:
jade
2026-08-25 16:37:08 +09:00
parent 53bc1487c8
commit d3cc1f7f33
47 changed files with 1377 additions and 252 deletions

View File

@@ -0,0 +1,19 @@
package io.shinhanlife.dat.mcc.biz.pro.converter;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryResponse;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io. DATNCSO00001_I;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io. DATNCSO00001_O;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PersonalCustomerDetailInquiryConverter {
// Field names differ? Add mappings like this before the method.
@Mapping(source = "customerId", target = "customerId")
DATNCSO00001_I toLegacyRequest(PersonalCustomerDetailInquiryRequest request);
PersonalCustomerDetailInquiryResponse toResponse( DATNCSO00001_O mciRes);
}

View File

@@ -0,0 +1,26 @@
package io.shinhanlife.dat.mcc.biz.pro.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.Pattern;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PersonalCustomerDetailInquiryRequest {
@Schema(description = "조회할 고객의 고유 ID (형식: ^[A-Za-z0-9-]{1,20}$) (예시: 12345, CUST-00123)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
@Pattern(regexp = "^[A-Za-z0-9-]{1,20}$")
private String customerId;
@Schema(description = "고객 이름 (선택적 확인용) (형식: ^[가-힣a-zA-Z\s]{2,20}$) (예시: 김철수, Lee Chul-soo)", example = "김철수")
@Pattern(regexp = "^[가-힣a-zA-Z\s]{2,20}$")
private String name;
@Schema(description = "고객 전화번호 (선택적 확인용) (형식: $) (예시: 010-1234-5678, +821012345678)", example = "010-1234-5678")
private String phoneNumber;
@Schema(description = "고객 이메일 주소 (선택적 확인용) (형식: $) (예시: customer@example.com, user@test.co.kr)", example = "customer@example.com")
private String email;
}

View File

@@ -0,0 +1,35 @@
package io.shinhanlife.dat.mcc.biz.pro.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 PersonalCustomerDetailInquiryResponse {
private String resultCode;
private String resultMessage;
@Schema(description = "조회된 고객의 고유 ID (예시: 12345, CUST-00123)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
private String customerId;
@Schema(description = "고객의 전체 이름 (예시: 김철수, Lee Chul-soo)", example = "김철수", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "고객의 전화번호 (예시: 010-1234-5678)", example = "010-1234-5678", requiredMode = Schema.RequiredMode.REQUIRED)
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (예시: customer@example.com)", example = "customer@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
private String email;
@Schema(description = "고객의 주소 정보 (예시: 서울시 강남구 테헤란로 123)", example = "서울시 강남구 테헤란로 123")
private String address;
@Schema(description = "고객의 생년월일 (예시: 1990-01-15)", example = "1990-01-15")
private String birthDate;
@Schema(description = "고객의 멤버십 등급 (예시: GOLD, SILVER, BRONZE)", example = "GOLD")
private String membershipLevel;
}

View File

@@ -0,0 +1,41 @@
package io.shinhanlife.dat.mcc.biz.pro.usecase;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dat.lib.annotation.GrowToolHint;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryResponse;
/**
* @package io.shinhanlife.dat.mcc.biz.pro.usecase
* @className PersonalCustomerDetailInquiryUseCase
* @description AX HUB 시스템 처리 클래스
* @author jade
* @create 2026.08.25
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.08.25 jade 최초생성
*
* </pre>
*/
public interface PersonalCustomerDetailInquiryUseCase {
@McpTool(name = "pro_personal_inquiry", title = "개인고객 상세 정보 조회", description = "개인고객의 상세 정보를 조회하는 도구로, 고객 ID 또는 기본 정보를 통해 이름, 연락처, 주소, 생년월일, 멤버십 등급 등 개인 고객 정보를 안전하게 조회할 수 있습니다.")
@GrowToolHint(
requiresApproval = false,
categoryKey = "pro",
mappingId = " DATNCSO00001",
functionDescription = "고객 ID 또는 기본 정보를 기반으로 개인 고객의 상세 정보를 조회하고 반환하는 핵심 비즈니스 함수입니다.",
whenToUse = "개인 고객의 상세 정보가 필요한 경우, 예를 들어 고객 ID, 이름, 전화번호, 이메일 등을 입력하여 고객 정보를 조회하고자 할 때 이 도구를 선택해야 합니다.",
whenNotToUse = "개인 고객이 아닌 법인 고객 정보 조회, 익명 또는 비개인 정보 요청, 또는 개인 정보 보호 정책상 정보 조회가 제한된 경우 이 도구를 선택하지 않아야 합니다.",
ioLimits = "입력 필드는 고객 ID(필수) 및 선택적 이름, 전화번호, 이메일을 허용하며, 최대 10개의 필드를 포함할 수 있습니다. 출력 필드는 결과 코드, 고객 ID, 이름, 전화번호, 이메일, 주소, 생년월일, 멤버십 등급 등을 포함하며, 최대 10개의 필드를 반환할 수 있습니다.",
displayDescription = "개인 고객의 상세 정보를 조회하는 포털용 간략한 설명으로, 이름, 연락처, 주소, 생년월일, 멤버십 등급 등을 확인할 수 있습니다.",
exampleQueries = {"고객 ID 12345로 개인 고객 정보를 조회해줘", "김철수 고객의 상세 정보를 알려줘", "010-1234-5678로 등록된 개인 고객 정보를 조회해줘", "lee@example.com 이메일로 가입된 개인 고객 정보를 조회해줘"},
destructive = false,
idempotent = true,
tags = {"고객관리", "조회"},
ownerOrg = "MCP_TOOL"
)
PersonalCustomerDetailInquiryResponse execute(PersonalCustomerDetailInquiryRequest req);
}

View File

@@ -0,0 +1,69 @@
package io.shinhanlife.dat.mcc.biz.pro.usecase.impl;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryResponse;
import io.shinhanlife.dat.mcc.biz.pro.usecase.PersonalCustomerDetailInquiryUseCase;
import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;
import io.shinhanlife.glow.communication.dto.Transfer;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import io.shinhanlife.dat.mcc.biz.pro.converter.PersonalCustomerDetailInquiryConverter;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io. DATNCSO00001_I;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io. DATNCSO00001_O;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.MciNcscClient;
/**
* @package io.shinhanlife.dat.mcc.biz.pro.usecase.impl
* @className PersonalCustomerDetailInquiryUseCaseImpl
* @description AX HUB 시스템 처리 클래스
* @author jade
* @create 2026.08.25
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.08.25 jade 최초생성
*
* </pre>
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PersonalCustomerDetailInquiryUseCaseImpl implements PersonalCustomerDetailInquiryUseCase {
private final MciNcscClient mci;
private final PersonalCustomerDetailInquiryConverter converter;
@Override
public PersonalCustomerDetailInquiryResponse execute(PersonalCustomerDetailInquiryRequest req) {
log.info("[MCI Tool] {} 요청 수신.", "pro_personal_inquiry");
try {
// MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO)
DATNCSO00001_I mciReq = converter.toLegacyRequest(req);
Transfer< DATNCSO00001_O> resTransfer = mci.callTo(
" DATNCSO00001",
null,
mciReq,
DATNCSO00001_O.class
);
PersonalCustomerDetailInquiryResponse response = new PersonalCustomerDetailInquiryResponse();
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 (Exception e) {
log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e);
PersonalCustomerDetailInquiryResponse response = new PersonalCustomerDetailInquiryResponse();
response.setResultCode("ERROR");
response.setResultMessage(e.getMessage() != null ? e.getMessage() : "Unknown error");
return response;
}
}
}

View File

@@ -0,0 +1,30 @@
package io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c;
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.ncs.c
* @className MciNcscClient
* @description AX HUB 시스템 처리 클래스
* @author jade
* @create 2026.08.25
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.08.25 jade 최초생성
*
* </pre>
*/
@Component
@RequiredArgsConstructor
public class MciNcscClient {
private final AxhubMciComponent mci;
public <O> Transfer<O> callTo(String interfaceId, String dummy, Object mciReq, Class<O> resType) throws Exception {
return mci.callTo(interfaceId, dummy, mciReq, resType);
}
}

View File

@@ -0,0 +1,24 @@
package io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.Pattern;
@Data
public class DATNCSO00001_I {
@Schema(description = "조회할 고객의 고유 ID (형식: ^[A-Za-z0-9-]{1,20}$) (예시: 12345, CUST-00123)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
@Pattern(regexp = "^[A-Za-z0-9-]{1,20}$")
private String customerId;
@Schema(description = "고객 이름 (선택적 확인용) (형식: ^[가-힣a-zA-Z\s]{2,20}$) (예시: 김철수, Lee Chul-soo)", example = "김철수")
@Pattern(regexp = "^[가-힣a-zA-Z\s]{2,20}$")
private String name;
@Schema(description = "고객 전화번호 (선택적 확인용) (형식: {4}$) (예시: 010-1234-5678, +821012345678)", example = "010-1234-5678")
private String phoneNumber;
@Schema(description = "고객 이메일 주소 (선택적 확인용) (형식: $) (예시: customer@example.com, user@test.co.kr)", example = "customer@example.com")
private String email;
}

View File

@@ -0,0 +1,33 @@
package io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class DATNCSO00001_O {
@Schema(description = "조회 결과 상태 코드 (예시: SUCCESS, ERROR_001)", example = "SUCCESS", requiredMode = Schema.RequiredMode.REQUIRED)
private String resultCode;
@Schema(description = "조회된 고객의 고유 ID (예시: 12345, CUST-00123)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
private String customerId;
@Schema(description = "고객의 전체 이름 (예시: 김철수, Lee Chul-soo)", example = "김철수", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "고객의 전화번호 (예시: 010-1234-5678)", example = "010-1234-5678", requiredMode = Schema.RequiredMode.REQUIRED)
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (예시: customer@example.com)", example = "customer@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
private String email;
@Schema(description = "고객의 주소 정보 (예시: 서울시 강남구 테헤란로 123)", example = "서울시 강남구 테헤란로 123")
private String address;
@Schema(description = "고객의 생년월일 (예시: 1990-01-15)", example = "1990-01-15")
private String birthDate;
@Schema(description = "고객의 멤버십 등급 (예시: GOLD, SILVER, BRONZE)", example = "GOLD")
private String membershipLevel;
}

View File

@@ -0,0 +1,10 @@
{
"resultCode" : "SUCCESS",
"customerId" : "12345",
"name" : "김철수",
"phoneNumber" : "010-1234-5678",
"email" : "customer@example.com",
"address" : "서울시 강남구 테헤란로 123",
"birthDate" : "1990-01-15",
"membershipLevel" : "GOLD"
}

View File

@@ -0,0 +1,16 @@
package io.shinhanlife.dat.mcc.biz.pro.usecase;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.PersonalCustomerDetailInquiryResponse;
import org.junit.jupiter.api.Test;
class PersonalCustomerDetailInquiryUseCaseTest {
@Test
void createsToolRequestAndResponseDtos() {
assertNotNull(new PersonalCustomerDetailInquiryRequest());
assertNotNull(new PersonalCustomerDetailInquiryResponse());
}
}