refactor: remove claim schema sample tool
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1m56s

This commit is contained in:
jade
2026-08-12 00:10:04 +09:00
parent 8cbdd2ecad
commit b60b933a08
11 changed files with 4 additions and 543 deletions

View File

@@ -144,7 +144,7 @@ UI에서 사용하는 Tailwind CSS와 Chart.js는 `dap-gateway/src/main/resource
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "cmm_claim_schema_search",
"name": "cmm_claim_search",
"arguments": {
"claimNo": "CLM2026070100120"
}
@@ -171,7 +171,7 @@ Tool 함수명은 아래 4단계 규칙을 사용합니다.
```text
pod_domain_service_action
예: cmm_claim_schema_search
예: cmm_claim_search
```
- `pod`: Tool Pod 식별자 (`oth`, `sms` 등)

View File

@@ -1,58 +0,0 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springaicommunity.mcp.annotation.McpToolParam;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 보험금 청구 조회 Tool의 입력 DTO 샘플이다.
* 청구번호 또는 계약번호 중 하나를 반드시 입력받는다.
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ClaimSearchRequest {
@McpToolParam(description = "청구번호. CLM 다음 숫자 13자리 형식이다.")
@Schema(pattern = "^CLM[0-9]{13}$", example = "CLM2026070100123")
private String claimNo;
@McpToolParam(description = "계약번호. 숫자 11자리 형식이다.")
@Schema(pattern = "^[0-9]{11}$", example = "10023456789")
private String contractNo;
@McpToolParam(description = "청구 상태 필터")
@Schema(example = "RECEIVED", allowableValues = {
"RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED",
"APPROVED", "PAID", "REJECTED", "WITHDRAWN"
})
private String status;
@McpToolParam(description = "청구 유형 필터")
@Schema(example = "MEDICAL", allowableValues = {
"MEDICAL", "SURGERY", "HOSPITALIZATION",
"DIAGNOSIS", "DEATH", "DISABILITY"
})
private String claimType;
@McpToolParam(description = "접수일 조회 시작일(YYYY-MM-DD)")
@Schema(format = "date", example = "2026-01-01")
private String fromDate;
@McpToolParam(description = "접수일 조회 종료일(YYYY-MM-DD)")
@Schema(format = "date", example = "2026-07-31")
private String toDate;
@McpToolParam(description = "반환할 최대 건수 (기본값: 20, 최대: 50)")
@Schema(pattern = "^[1-9][0-9]?$|^50$", defaultValue = "20", example = "20")
private String size;
}

View File

@@ -1,87 +0,0 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springaicommunity.mcp.annotation.McpToolParam;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* Claim search response sample.
* Complex response rules are defined by outputSchemaResource; annotations document
* the same simple field constraints for automatic schema generation examples.
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ClaimSearchResponse {
@McpToolParam(description = "Execution result code.")
@Schema(required = true, allowableValues = {"SUCCESS", "FAILURE"})
private String resultCode;
@McpToolParam(description = "User-readable label for resultCode.")
@Schema(required = true, maxLength = 100)
private String resultLabel;
@McpToolParam(description = "Current claim processing status code.")
@Schema(required = true, allowableValues = {
"RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED",
"APPROVED", "PAID", "REJECTED", "WITHDRAWN"
})
private String status;
@McpToolParam(description = "User-readable label for status.")
@Schema(required = true, maxLength = 100)
private String statusLabel;
@McpToolParam(description = "Approved amount. Null before review; do not interpret null as zero.")
@Schema(minimum = "0", nullable = true)
private Long approvedAmount;
@McpToolParam(description = "Present only when status is REJECTED; otherwise null.")
@Schema(maxLength = 200, nullable = true)
private String rejectionReason;
@McpToolParam(description = "Claim summaries, ordered by received date descending.")
@Schema(required = true)
private List<ClaimSummary> items;
@McpToolParam(description = "True when additional results exist beyond this response.")
@Schema(required = true)
private Boolean hasMore;
@McpToolParam(description = "Total number of matched claims.")
@Schema(required = true, nullable = true)
private Integer totalCount;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ClaimSummary {
@McpToolParam(description = "Claim processing status code.")
private String status;
@McpToolParam(description = "User-readable label for status.")
private String statusLabel;
@McpToolParam(description = "Received date in YYYY-MM-DD format.")
@Schema(required = true, format = "date")
private String receivedDate;
@McpToolParam(description = "Approved amount. Null before review; do not interpret null as zero.")
@Schema(nullable = true)
private Long approvedAmount;
}
}

View File

@@ -1,16 +0,0 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchRequest;
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse;
public interface ClaimSearchSchemaSampleUseCase {
@McpTool(name = "cmm_claim_schema_search", title = "청구 조회 스키마 샘플", description = "Claim search Tool sample using input and output JSON Schema resources.", annotations = @McpTool.McpAnnotations(readOnlyHint = true, idempotentHint = true))
@ToolHint(register = false, categoryKey = "cmm",
inputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-input-schema.json",
outputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-output-schema.json")
ClaimSearchResponse search(ClaimSearchRequest request);
}

View File

@@ -1,36 +0,0 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl;
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchRequest;
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse;
import io.shinhanlife.dap.mcc.biz.cmm.usecase.ClaimSearchSchemaSampleUseCase;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* Non-exposed sample Tool. It does not call MCI or EIMS.
*/
@Service
public class ClaimSearchSchemaSampleUseCaseImpl implements ClaimSearchSchemaSampleUseCase {
@Override
public ClaimSearchResponse search(ClaimSearchRequest request) {
ClaimSearchResponse.ClaimSummary item = ClaimSearchResponse.ClaimSummary.builder()
.status("REVIEWING")
.statusLabel("Under review")
.receivedDate("2026-08-04")
.approvedAmount(null)
.build();
return ClaimSearchResponse.builder()
.resultCode("SUCCESS")
.resultLabel("Success")
.status("REVIEWING")
.statusLabel("Under review")
.approvedAmount(null)
.rejectionReason(null)
.items(List.of(item))
.hasMore(false)
.totalCount(1)
.build();
}
}

View File

@@ -5,7 +5,7 @@ import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.oth.dto.*;
public interface Onnba3011UseCase {
@McpTool(name = "onnba3011_call", description = "Onnba3011 호출 툴")
@McpTool(name = "oth_onnba3011_call", description = "Onnba3011 호출 툴")
@ToolHint(categoryKey = "oth", register = false)
Object execute(Onnba3011Request req);
}

View File

@@ -1,49 +0,0 @@
{
"type": "object",
"additionalProperties": false,
"properties": {
"claimNo": {
"type": "string",
"description": "청구번호. CLM 이후 숫자 13자리 형식입니다.",
"pattern": "^CLM[0-9]{13}$",
"example": "CLM2026070100123"
},
"contractNo": {
"type": "string",
"description": "계약번호. 숫자 11자리 형식입니다.",
"pattern": "^[0-9]{11}$",
"example": "10023456789"
},
"status": {
"type": "string",
"description": "청구 상태 필터",
"enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"],
"example": "RECEIVED"
},
"claimType": {
"type": "string",
"description": "청구 유형 필터",
"enum": ["MEDICAL", "SURGERY", "HOSPITALIZATION", "DIAGNOSIS", "DEATH", "DISABILITY"],
"example": "MEDICAL"
},
"fromDate": {
"type": "string",
"description": "접수일 조회 시작일 (YYYY-MM-DD)",
"format": "date",
"example": "2026-01-01"
},
"toDate": {
"type": "string",
"description": "접수일 조회 종료일 (YYYY-MM-DD)",
"format": "date",
"example": "2026-07-31"
},
"size": {
"type": "string",
"description": "반환할 최대 건수 (기본값: 20, 최대: 50)",
"pattern": "^[1-9][0-9]?$|^50$",
"default": "20",
"example": "20"
}
}
}

View File

@@ -1,83 +0,0 @@
{
"type": "object",
"additionalProperties": false,
"properties": {
"resultCode": {
"type": "string",
"description": "실행 결과 코드",
"enum": ["SUCCESS", "FAILURE"]
},
"resultLabel": {
"type": "string",
"description": "resultCode의 사용자 표시 라벨",
"maxLength": 100
},
"status": {
"type": "string",
"description": "현재 청구 처리 상태 코드",
"enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"]
},
"statusLabel": {
"type": "string",
"description": "status의 사용자 표시 라벨",
"maxLength": 100
},
"approvedAmount": {
"anyOf": [
{"type": "integer", "minimum": 0},
{"type": "null"}
],
"description": "승인 금액. 심사 전에는 null이며 0으로 해석하지 않습니다."
},
"rejectionReason": {
"anyOf": [
{"type": "string", "maxLength": 200},
{"type": "null"}
],
"description": "status가 REJECTED일 때만 존재하며, 그 외에는 null입니다."
},
"items": {
"type": "array",
"description": "수령일 내림차순으로 정렬된 청구 요약 목록",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"type": "string",
"description": "청구 처리 상태 코드"
},
"statusLabel": {
"type": "string",
"description": "status의 사용자 표시 라벨"
},
"receivedDate": {
"type": "string",
"description": "접수일 (YYYY-MM-DD 형식)",
"format": "date"
},
"approvedAmount": {
"anyOf": [
{"type": "integer", "minimum": 0},
{"type": "null"}
],
"description": "승인 금액. 심사 전에는 null"
}
},
"required": ["receivedDate"]
}
},
"hasMore": {
"type": "boolean",
"description": "이 응답 이후 추가 결과가 있는지 여부"
},
"totalCount": {
"anyOf": [
{"type": "integer", "minimum": 0},
{"type": "null"}
],
"description": "매칭된 청구 건수 합계"
}
},
"required": ["resultCode", "resultLabel", "status", "statusLabel", "items", "hasMore"]
}

View File

@@ -1,37 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"claimNo": {
"type": "string",
"description": "청구번호. CLM 다음 숫자 13자리 형식이다.",
"pattern": "^CLM[0-9]{13}$",
"examples": ["CLM2026070100123"]
},
"contractNo": {
"type": "string",
"description": "계약번호. 숫자 11자리 형식이다.",
"pattern": "^[0-9]{11}$",
"examples": ["10023456789"]
},
"status": {
"type": "string",
"enum": [
"RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED",
"APPROVED", "PAID", "REJECTED", "WITHDRAWN"
]
},
"size": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"default": 20
}
},
"required": [],
"additionalProperties": false,
"anyOf": [
{ "required": ["claimNo"] },
{ "required": ["contractNo"] }
]
}

View File

@@ -1,81 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"description": "Claim search response. This schema intentionally excludes employee identifiers, customer names, contact details, account information, and other PII.",
"properties": {
"resultCode": {
"type": "string",
"enum": ["SUCCESS", "FAILURE"],
"description": "Machine-readable execution result code."
},
"resultLabel": {
"type": "string",
"description": "User-readable label for resultCode."
},
"status": {
"type": "string",
"enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"],
"description": "Current claim processing status code."
},
"statusLabel": {
"type": "string",
"description": "User-readable label for status."
},
"approvedAmount": {
"anyOf": [
{ "type": "number", "minimum": 0 },
{ "type": "null" }
],
"description": "Approved amount. It is null before review and must not be interpreted as zero."
},
"rejectionReason": {
"type": ["string", "null"],
"maxLength": 200,
"description": "Has a value only when status is REJECTED. It is null for every other status."
},
"items": {
"type": "array",
"description": "Claim summaries ordered by receivedDate descending. No personally identifiable information is included.",
"items": {
"type": "object",
"properties": {
"status": { "type": "string", "description": "Claim status code." },
"statusLabel": { "type": "string", "description": "User-readable label for status." },
"receivedDate": { "type": "string", "format": "date", "description": "Claim received date." },
"approvedAmount": {
"anyOf": [
{ "type": "number", "minimum": 0 },
{ "type": "null" }
],
"description": "Null before review; do not interpret as zero."
}
},
"required": ["status", "statusLabel", "receivedDate"],
"additionalProperties": false
}
},
"hasMore": {
"type": "boolean",
"description": "True when additional results exist beyond this response."
},
"totalCount": {
"type": "integer",
"minimum": 0,
"description": "Total number of matched claims."
}
},
"required": ["resultCode", "resultLabel", "status", "statusLabel", "items", "hasMore", "totalCount"],
"allOf": [
{
"if": {
"properties": { "status": { "const": "REJECTED" } },
"required": ["status"]
},
"then": {
"properties": { "rejectionReason": { "type": "string", "minLength": 1 } },
"required": ["rejectionReason"]
}
}
],
"additionalProperties": false
}

View File

@@ -1,92 +0,0 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.lib.util.JsonSchemaGenerator;
import io.shinhanlife.dap.lib.util.ToolSchemaResolver;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.usecase.impl.ClaimSearchSchemaSampleUseCaseImpl;
import io.shinhanlife.dap.lib.validation.ToolArgumentSchemaValidator;import io.shinhanlife.dap.mcc.biz.cmm.usecase.ClaimSearchSchemaSampleUseCase;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springaicommunity.mcp.annotation.McpTool;
class ClaimSearchRequestSchemaTest {
@Test
void generatesClaimOrContractSearchSchema() {
Map<String, Object> schema = JsonSchemaGenerator.generateSchema(ClaimSearchRequest.class);
Map<String, Map<String, Object>> properties = properties(schema);
assertEquals(false, schema.get("additionalProperties"));
assertEquals("^CLM[0-9]{13}$", properties.get("claimNo").get("pattern"));
assertEquals("^[1-9][0-9]?$|^50$", properties.get("size").get("pattern"));
assertEquals("20", properties.get("size").get("default"));
assertFalse(schema.containsKey("anyOf"));
}
@Test
void resolvesSchemaFromToolModuleResource() throws Exception {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
McpTool function = method.getAnnotation(McpTool.class);
ToolHint hint = method.getAnnotation(ToolHint.class);
Map<String, Object> schema = new ToolSchemaResolver(new ObjectMapper())
.resolve(function, hint, ClaimSearchRequest.class);
assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema"));
assertTrue(schema.containsKey("anyOf"));
assertEquals(50, property(schema, "size").get("maximum"));
}
@Test
void resolvesOutputSchemaFromToolModuleResource() throws Exception {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
McpTool function = method.getAnnotation(McpTool.class);
ToolHint hint = method.getAnnotation(ToolHint.class);
Map<String, Object> schema = new ToolSchemaResolver(new ObjectMapper())
.resolveOutput(function, ClaimSearchResponse.class, hint);
assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema"));
assertTrue(properties(schema).containsKey("resultCode"));
assertTrue(properties(schema).containsKey("statusLabel"));
assertTrue(properties(schema).containsKey("hasMore"));
assertTrue(schema.containsKey("allOf"));
}
@Test
void sampleResponseConformsToOutputSchema() throws Exception {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
Map<String, Object> schema = new ToolSchemaResolver(new ObjectMapper())
.resolveOutput(method.getAnnotation(McpTool.class), ClaimSearchResponse.class,
method.getAnnotation(ToolHint.class));
ClaimSearchResponse response = new ClaimSearchSchemaSampleUseCaseImpl().search(new ClaimSearchRequest());
ToolArgumentSchemaValidator validator = new ToolArgumentSchemaValidator(new ObjectMapper());
assertTrue(validator.validateValue(schema, response).isEmpty());
}
@Test
void sampleResponseConformsToAutomaticallyGeneratedOutputSchema() throws Exception {
Map<String, Object> schema = JsonSchemaGenerator.generateSchema(ClaimSearchResponse.class);
ClaimSearchResponse response = new ClaimSearchSchemaSampleUseCaseImpl().search(new ClaimSearchRequest());
ToolArgumentSchemaValidator validator = new ToolArgumentSchemaValidator(new ObjectMapper());
assertTrue(validator.validateValue(schema, response).isEmpty());
}
@SuppressWarnings("unchecked")
private Map<String, Map<String, Object>> properties(Map<String, Object> schema) {
return (Map<String, Map<String, Object>>) schema.get("properties");
}
private Map<String, Object> property(Map<String, Object> schema, String name) {
return properties(schema).get(name);
}
}