소스 업데이트
All checks were successful
Deploy Tools / deploy (push) Successful in 52s

This commit is contained in:
jade
2026-08-25 17:49:04 +09:00
parent 87249a621c
commit 935702a569
10 changed files with 313 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package io.shinhanlife.dat.mcc.biz.pro.converter;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryResponse;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io.ONCSC1340_I;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io.ONCSC1340_O;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface IndividualCustomerDetailInquiryConverter {
// Field names differ? Add mappings like this before the method.
// @Mapping(source = "sourceField", target = "targetField")
ONCSC1340_I toLegacyRequest(IndividualCustomerDetailInquiryRequest request);
IndividualCustomerDetailInquiryRequest toRequest(ONCSC1340_I mciRequest);
IndividualCustomerDetailInquiryResponse toResponse(ONCSC1340_O mciRes);
}

View File

@@ -0,0 +1,29 @@
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 IndividualCustomerDetailInquiryRequest {
@Schema(description = "조회할 고객의 고유 ID (형식: ^[A-Za-z0-9]{1,20}$) (예시: 12345, CUST00001)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
@Pattern(regexp = "^[A-Za-z0-9]{1,20}$")
private String customerId;
@Schema(description = "고객의 이름 (선택적 검색 조건) (형식: ^[가-힣a-zA-Z\s]{2,50}$) (예시: 김철수, 이영희)", example = "김철수")
@Pattern(regexp = "^[가-힣a-zA-Z\s]{2,50}$")
private String name;
@Schema(description = "고객의 연락처 번호 (선택적 검색 조건) (형식: {10,11}$) (예시: 010-1234-5678, 01012345678)", example = "010-1234-5678")
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (선택적 검색 조건) (형식: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$) (예시: test@example.com, user@test.co.kr)", example = "test@example.com")
private String email;
@Schema(description = "고객의 생년월일 (선택적 검색 조건, YYYY-MM-DD 형식) (형식: {2}$) (예시: 1990-01-15, 1985-12-31)", example = "1990-01-15")
private String birthDate;
}

View File

@@ -0,0 +1,36 @@
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 IndividualCustomerDetailInquiryResponse {
private String resultCode;
private String resultMessage;
@Schema(description = "고객의 고유 ID (예시: 12345, CUST00001)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
private String customerId;
@Schema(description = "고객의 전체 이름 (예시: 김철수, 이영희)", example = "김철수", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "고객의 연락처 번호 (예시: 010-1234-5678, 01012345678)", example = "010-1234-5678", requiredMode = Schema.RequiredMode.REQUIRED)
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (예시: test@example.com, user@test.co.kr)", example = "test@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
private String email;
@Schema(description = "고객의 주소 정보 (예시: 서울시 강남구 테헤란로 123, 부산시 해운대구 해운대해변로 456)", example = "서울시 강남구 테헤란로 123", requiredMode = Schema.RequiredMode.REQUIRED)
private String address;
@Schema(description = "고객 가입일 (형식: $) (예시: 2023-01-15, 2022-11-30)", example = "2023-01-15", requiredMode = Schema.RequiredMode.REQUIRED)
private String registrationDate;
@Schema(description = "고객 등급 정보 (예시: VIP, GOLD, SILVER, BRONZE)", example = "VIP")
private String grade;
}

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.IndividualCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryResponse;
/**
* @package io.shinhanlife.dat.mcc.biz.pro.usecase
* @className IndividualCustomerDetailInquiryUseCase
* @description AX HUB 시스템 처리 클래스
* @author jade
* @create 2026.08.25
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.08.25 jade 최초생성
*
* </pre>
*/
public interface IndividualCustomerDetailInquiryUseCase {
@McpTool(name = "pro_individual_inquiry", title = "개인고객 상세조회", description = "개인고객의 상세 정보를 조회하는 도구로, 기본 정보부터 연락처, 주소까지 모든 고객 데이터를 제공합니다.")
@GrowToolHint(
requiresApproval = false,
categoryKey = "pro",
mappingId = "DATNCSO00001",
functionDescription = "등록된 개인고객의 상세 정보를 조회하여 고객 관리 및 서비스 제공에 필요한 모든 데이터를 반환합니다.",
whenToUse = "특정 고객의 상세 정보가 필요한 경우, 예를 들어 고객 지원, 마케팅, 또는 서비스 제공 시 사용됩니다.",
whenNotToUse = "집계된 통계 데이터만 필요한 경우, 개별 고객 정보 조회는 적합하지 않습니다.",
ioLimits = "최대 100명의 고객 정보를 한 번에 조회할 수 있으며, 각 고객 정보는 최대 5KB까지 지원됩니다.",
displayDescription = "개인고객의 모든 상세 정보를 한눈에 확인할 수 있는 조회 도구입니다.",
exampleQueries = {"고객 ID 12345에 대한 상세 정보를 조회해주세요.", "김철수 고객의 연락처 정보를 알려주세요.", "주민등록번호 800101-123456으로 등록된 고객의 주소를 조회해주세요.", "최근 가입한 고객 10명의 정보를 조회해주세요.", "이메일 주소가 test@example.com인 고객의 상세 정보를 찾아주세요.", "전화번호가 010-1234-5678인 고객의 정보를 조회해주세요.", "2023년에 가입한 고객의 상세 정보를 조회해주세요.", "주소가 서울인 고객의 정보를 조회해주세요.", "VIP 등급의 고객 정보를 조회해주세요.", "최근 30일 이내에 활동한 고객의 상세 정보를 조회해주세요.", "고객 ID 99999에 대한 모든 정보를 조회해주세요.", "고객 이름 '이영희'로 검색해주세요.", "마지막 활동일이 지난 고객의 정보를 조회해주세요.", "마케팅 동의한 고객의 연락처 정보를 조회해주세요.", "신규 가입 고객의 기본 정보를 조회해주세요."},
destructive = false,
idempotent = true,
tags = {"customer", "inquiry"},
ownerOrg = "MCP_TOOL"
)
IndividualCustomerDetailInquiryResponse execute(IndividualCustomerDetailInquiryRequest req);
}

View File

@@ -0,0 +1,69 @@
package io.shinhanlife.dat.mcc.biz.pro.usecase.impl;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryResponse;
import io.shinhanlife.dat.mcc.biz.pro.usecase.IndividualCustomerDetailInquiryUseCase;
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.IndividualCustomerDetailInquiryConverter;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io.ONCSC1340_I;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.io.ONCSC1340_O;
import io.shinhanlife.dat.mcc.infra.itrf.mci.ncs.c.MciNcscClient;
/**
* @package io.shinhanlife.dat.mcc.biz.pro.usecase.impl
* @className IndividualCustomerDetailInquiryUseCaseImpl
* @description AX HUB 시스템 처리 클래스
* @author jade
* @create 2026.08.25
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.08.25 jade 최초생성
*
* </pre>
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class IndividualCustomerDetailInquiryUseCaseImpl implements IndividualCustomerDetailInquiryUseCase {
private final MciNcscClient mci;
private final IndividualCustomerDetailInquiryConverter converter;
@Override
public IndividualCustomerDetailInquiryResponse execute(IndividualCustomerDetailInquiryRequest req) {
log.info("[MCI Tool] {} 요청 수신.", "pro_individual_inquiry");
try {
// MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO)
ONCSC1340_I mciReq = converter.toLegacyRequest(req);
Transfer<ONCSC1340_O> resTransfer = mci.callTo(
"DATNCSO00001",
null,
mciReq,
ONCSC1340_O.class
);
IndividualCustomerDetailInquiryResponse response = new IndividualCustomerDetailInquiryResponse();
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);
IndividualCustomerDetailInquiryResponse response = new IndividualCustomerDetailInquiryResponse();
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,29 @@
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 ONCSC1340_I {
@Schema(description = "조회할 고객의 고유 ID (형식: ^[A-Za-z0-9]{1,20}$) (예시: 12345, CUST00001)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
@Pattern(regexp = "^[A-Za-z0-9]{1,20}")
private String customerId;
@Schema(description = "고객의 이름 (선택적 검색 조건) (형식: ^[가-힣a-zA-Z\s]{2,50}$) (예시: 김철수, 이영희)", example = "김철수")
@Pattern(regexp = "^[가-힣a-zA-Zs]{2,50}")
private String name;
@Schema(description = "고객의 연락처 번호 (선택적 검색 조건) (형식: 10,11}$) (예시: 010-1234-5678, 01012345678)", example = "010-1234-5678")
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (선택적 검색 조건) (형식: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$) (예시: test@example.com, user@test.co.kr)", example = "test@example.com")
@Pattern(regexp = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}")
private String email;
@Schema(description = "고객의 생년월일 (선택적 검색 조건, YYYY-MM-DD 형식) (형식: ^d{4}-d{2}-d{2}$) (예시: 1990-01-15, 1985-12-31)", example = "1990-01-15")
@Pattern(regexp = "d{4}-d{2}-d{2}")
private String birthDate;
}

View File

@@ -0,0 +1,35 @@
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 ONCSC1340_O {
@Schema(description = "조회 결과 코드 (예시: SUCCESS, ERROR_001)", example = "SUCCESS", requiredMode = Schema.RequiredMode.REQUIRED)
private String resultCode;
@Schema(description = "고객의 고유 ID (예시: 12345, CUST00001)", example = "12345", requiredMode = Schema.RequiredMode.REQUIRED)
private String customerId;
@Schema(description = "고객의 전체 이름 (예시: 김철수, 이영희)", example = "김철수", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "고객의 연락처 번호 (예시: 010-1234-5678, 01012345678)", example = "010-1234-5678", requiredMode = Schema.RequiredMode.REQUIRED)
private String phoneNumber;
@Schema(description = "고객의 이메일 주소 (예시: test@example.com, user@test.co.kr)", example = "test@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
private String email;
@Schema(description = "고객의 주소 정보 (예시: 서울시 강남구 테헤란로 123, 부산시 해운대구 해운대해변로 456)", example = "서울시 강남구 테헤란로 123", requiredMode = Schema.RequiredMode.REQUIRED)
private String address;
@Schema(description = "고객 가입일 (형식: ^d{4}-d{2}-d{2}$) (예시: 2023-01-15, 2022-11-30)", example = "2023-01-15", requiredMode = Schema.RequiredMode.REQUIRED)
@Pattern(regexp = "^d{4}-d{2}-d{2}$")
private String registrationDate;
@Schema(description = "고객 등급 정보 (예시: VIP, GOLD, SILVER, BRONZE)", example = "VIP")
private String grade;
}

View File

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

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.IndividualCustomerDetailInquiryRequest;
import io.shinhanlife.dat.mcc.biz.pro.dto.IndividualCustomerDetailInquiryResponse;
import org.junit.jupiter.api.Test;
class IndividualCustomerDetailInquiryUseCaseTest {
@Test
void createsToolRequestAndResponseDtos() {
assertNotNull(new IndividualCustomerDetailInquiryRequest());
assertNotNull(new IndividualCustomerDetailInquiryResponse());
}
}