forked from kimhyungsik/ax_hub_mcp_tool
Initial commit
This commit is contained in:
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.git
|
||||
.gradle
|
||||
.idea
|
||||
/build/
|
||||
target/
|
||||
*/target/
|
||||
bin/
|
||||
*/bin/
|
||||
out/
|
||||
*/out/
|
||||
25
.gitattributes
vendored
Normal file
25
.gitattributes
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# 湲곕낯媛? 紐⑤뱺 ?띿뒪???뚯씪 CRLF (Windows 媛쒕컻 ?섍꼍)
|
||||
* text=auto eol=crlf
|
||||
|
||||
# Shell ?ㅽ겕由쏀듃??LF 怨좎젙 (Linux CI/CD ?ㅽ뻾 ?섍꼍)
|
||||
*.sh text eol=lf
|
||||
mvnw text eol=lf
|
||||
gradlew text eol=lf
|
||||
|
||||
# 諛붿씠?덈━ ?뚯씪 (以꾨컮轅?蹂???쒖쇅)
|
||||
*.jar binary
|
||||
*.war binary
|
||||
*.ear binary
|
||||
*.class binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.svg binary
|
||||
*.ttf binary
|
||||
*.woff binary
|
||||
*.woff2binary
|
||||
*.pdf binary
|
||||
*.zip binary
|
||||
*.tar.gz binary
|
||||
124
.gitignore
vendored
Normal file
124
.gitignore
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
# ===== 鍮뚮뱶 寃곌낵臾?=====
|
||||
target/
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
*.class
|
||||
*.jar
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.nar
|
||||
|
||||
# ===== 濡쒓렇 =====
|
||||
*.log
|
||||
logs/
|
||||
spring-shell.log
|
||||
|
||||
# ===== Maven =====
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
|
||||
# ===== IntelliJ IDEA =====
|
||||
.idea/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
|
||||
# ===== Eclipse / STS =====
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
|
||||
# ===== NetBeans =====
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
.gradle/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
# ===== VS Code =====
|
||||
.vscode/
|
||||
|
||||
# ===== 鍮뚮뱶 寃곌낵臾?=====
|
||||
target/
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
*.class
|
||||
*.jar
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.nar
|
||||
|
||||
# ===== 濡쒓렇 =====
|
||||
*.log
|
||||
logs/
|
||||
spring-shell.log
|
||||
|
||||
# ===== Maven =====
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
|
||||
# ===== IntelliJ IDEA =====
|
||||
.idea/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
|
||||
# ===== Eclipse / STS =====
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
|
||||
# ===== NetBeans =====
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
.gradle/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
# ===== VS Code =====
|
||||
.vscode/
|
||||
|
||||
# ===== OS =====
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# ===== ?섍꼍?ㅼ젙 (誘쇨컧?뺣낫 遺꾨━ ?? =====
|
||||
# application-local.yml
|
||||
# application-secret.yml
|
||||
0
AddJavadoc.java
Normal file
0
AddJavadoc.java
Normal file
50
Dockerfile
Normal file
50
Dockerfile
Normal file
@@ -0,0 +1,50 @@
|
||||
# 1. 빌드 환경 (JDK 21)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 외부 인터넷이 차단된 내부망에서는 Docker Hub 대신 사내 Container Registry의
|
||||
# Java 21 이미지를 사용합니다. 인프라 담당자에게 이미지의 전체 경로와 태그를
|
||||
# 받은 후 아래 FROM 행만 교체합니다.
|
||||
#
|
||||
# 예: FROM registry.shinhanlife.co.kr/base/openjdk:21 AS builder
|
||||
#
|
||||
# 이 단계는 Gradle 빌드와 Java 컴파일을 수행하므로 반드시 JDK 21 이미지여야 합니다.
|
||||
# 사내 이미지가 실제로 JDK 21인지 다음 명령으로 확인합니다.
|
||||
# docker run --rm <사내-JDK-이미지> java -version
|
||||
FROM eclipse-temurin:21-jdk-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Gradle Wrapper와 소스 파일을 복사합니다.
|
||||
COPY gradlew .
|
||||
COPY gradle gradle
|
||||
COPY build.gradle settings.gradle ./
|
||||
COPY src src
|
||||
|
||||
# Wrapper 실행 권한을 부여하고 테스트를 제외한 빌드를 수행합니다.
|
||||
RUN chmod +x gradlew
|
||||
RUN ./gradlew clean build -x test
|
||||
|
||||
# 2. 실행 환경 (JRE 21)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 실행 단계는 JRE 21 이미지가 가장 가볍지만, 사내에서 JDK 21 이미지만 제공하는
|
||||
# 경우에는 동일한 JDK 21 이미지를 사용해도 정상 동작합니다.
|
||||
#
|
||||
# 예: FROM registry.shinhanlife.co.kr/base/openjre:21
|
||||
# 예: FROM registry.shinhanlife.co.kr/base/openjdk:21
|
||||
#
|
||||
# 사내 제공 이미지의 기반 OS를 확인합니다.
|
||||
# - Alpine 기반: 아래 apk 명령을 그대로 사용합니다.
|
||||
# - Ubuntu/Debian 기반: apk 대신 apt-get update && apt-get install -y tzdata를 사용합니다.
|
||||
FROM eclipse-temurin:21-jre-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# 서울 시간대를 설정합니다.
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ=Asia/Seoul
|
||||
|
||||
# 빌드 단계에서 생성한 애플리케이션 JAR를 복사합니다.
|
||||
COPY --from=builder /app/build/libs/*.jar app.jar
|
||||
|
||||
# 애플리케이션 포트를 노출합니다.
|
||||
EXPOSE 8081
|
||||
|
||||
# 애플리케이션을 실행합니다.
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
0
McpBridge.java
Normal file
0
McpBridge.java
Normal file
268
README.md
Normal file
268
README.md
Normal file
@@ -0,0 +1,268 @@
|
||||
# DAP WAS Tool Pods
|
||||
|
||||
신한라이프 업무 시스템과 MCP(Model Context Protocol) 클라이언트를 연결하는 독립형 Tool WAS 프로젝트입니다. 이 저장소에는 Gateway가 포함되어 있지 않습니다. 각 Tool Pod가 직접 MCP Streamable HTTP와 REST 실행 API를 제공하고, 업무 요청은 `UseCase → Converter → MCI/EAI 연동`으로 처리합니다.
|
||||
|
||||
> 이 문서는 현재 `main`의 구현과 설정을 기준으로 합니다. 과거 `dap-gateway`, Chat API, SSE, 외부 Tool Registry/Heartbeat 관련 문서는 현재 저장소의 동작 범위가 아니므로 포함하지 않습니다.
|
||||
|
||||
## 구성
|
||||
|
||||
```text
|
||||
MCP Client
|
||||
├─ Streamable HTTP: /mcp
|
||||
└─ REST: POST /mcp/{tool-name}
|
||||
│
|
||||
▼
|
||||
Tool Pod (dap-was-oth 또는 dap-was-sms)
|
||||
│
|
||||
├─ LocalToolScanner: @McpTool / @McpFunction 메타데이터 생성
|
||||
├─ BusinessToolController: 입력 검증·DTO 변환·동적 실행
|
||||
├─ ToolManifestController: /tool-manifest 제공
|
||||
└─ UseCase → Converter → MCI/EAI Client → 대상 시스템
|
||||
```
|
||||
|
||||
## Gradle 모듈
|
||||
|
||||
| 모듈 | 역할 | 기본 포트 |
|
||||
|---|---|---:|
|
||||
| `dap-was-lib` | MCP 어노테이션, 스캐너, 실행 Controller, Manifest, Schema, MCI/EAI/로깅/보안 공통 기능 | - |
|
||||
| `dap-was-oth` | 공통·기타·샘플·SOL 업무 Tool Pod | 8084 |
|
||||
| `dap-was-sms` | SMS/알림 업무 Pod | 8082 |
|
||||
|
||||
기술 기준은 Java 21, Spring Boot 4.0.5, Gradle Wrapper 8.14.3, Spring AI MCP Server WebMVC, Redis, MapStruct, MyBatis, Resilience4j입니다.
|
||||
|
||||
## 현재 제공 API
|
||||
|
||||
아래 API는 각 Tool Pod가 직접 제공합니다. OTH Pod의 로컬 주소는 `http://localhost:8084`, SMS Pod는 `http://localhost:8082`입니다.
|
||||
|
||||
| 목적 | 메서드 | 경로 | 구현 |
|
||||
|---|---|---|---|
|
||||
| MCP Streamable HTTP 전송 | MCP 프로토콜 | `/mcp` | `ToolMcpServerConfiguration` |
|
||||
| Pod에서 스캔한 Tool 메타데이터 조회 | `GET` | `/mcp/api/v1/tools/local` | `BusinessToolController` |
|
||||
| 이름으로 Tool 직접 실행 | `POST` | `/mcp/{name}` | `BusinessToolController` |
|
||||
| Pod 소유 Manifest 조회 | `GET` | `/tool-manifest` | `ToolManifestController` |
|
||||
|
||||
`GET /tool-manifest`는 `If-None-Match` 요청 헤더를 지원하며, 내용이 바뀌지 않으면 `304 Not Modified`를 반환합니다. 응답에는 bundle ID, revision, Tool 목록, 입력 Schema, 실행 endpoint, annotation/meta 정보가 포함됩니다. Manifest는 `LocalToolScanner`의 전체 스캔 목록을 사용하므로 `visible = false` 또는 `register = false`인 항목도 포함될 수 있습니다.
|
||||
|
||||
`GET /mcp/api/v1/tools/local`은 Manifest 검증이나 MCP 세션을 열지 않고, 현재 Pod에서 스캔한 `ToolMetadata` 목록을 반환합니다.
|
||||
|
||||
### REST 실행 예시
|
||||
|
||||
Tool 이름은 `@McpFunction.name` 값입니다. 예를 들어 OTH Pod의 `oth.smp.weather.inquiry`는 다음처럼 호출합니다.
|
||||
|
||||
```powershell
|
||||
$headers = @{
|
||||
'trace-id' = 'trace-local-001'
|
||||
'request-id' = 'request-local-001'
|
||||
}
|
||||
|
||||
Invoke-RestMethod `
|
||||
-Method Post `
|
||||
-Uri 'http://localhost:8084/mcp/oth.smp.weather.inquiry' `
|
||||
-Headers $headers `
|
||||
-ContentType 'application/json' `
|
||||
-Body '{"city":"Seoul"}'
|
||||
```
|
||||
|
||||
Controller는 이름을 찾은 뒤 요청 JSON을 첫 번째 DTO 매개변수로 변환합니다. 입력 Schema 검증 실패는 `422 INVALID_PARAM`, 존재하지 않는 Tool은 `404 TOOL_NOT_FOUND`, 실행 예외는 `502 TOOL_ERROR` 응답입니다. `trace-id`와 `request-id`는 성공 응답 헤더로 다시 전달됩니다.
|
||||
|
||||
## Tool 검색과 MCP 노출 규칙
|
||||
|
||||
애플리케이션 기동 시 `LocalToolScanner`는 Spring Bean에서 `@McpTool`과 `@McpFunction` 메타데이터를 읽어 로컬 Tool 목록을 만듭니다. 기동 완료 후 `ToolPodMcpToolSynchronizer`는 이 목록 중 `visible = true`인 Tool만 MCP SDK 서버에 추가합니다.
|
||||
|
||||
| 속성 | 현재 구현에서의 의미 |
|
||||
|---|---|
|
||||
| `visible` | `false`이면 MCP SDK의 Tool 등록에서 제외됩니다. |
|
||||
| `register` | 스캐너 메타데이터의 `isRegistered` 값과 내부 `registeredTools` 목록에만 반영됩니다. 현재 저장소에는 외부 Registry 전송 구현이 없습니다. |
|
||||
| `namespace` | 비어 있지 않으면 Tool 이름 앞에 `{namespace}_`가 붙습니다. 기본 설정은 빈 문자열입니다. |
|
||||
| `enabled` | Manifest의 `_meta.enabled` 값으로 노출됩니다. 현재 synchronizer는 이 값으로 별도 필터링하지 않습니다. |
|
||||
| `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` | MCP Tool annotation과 Manifest annotation에 반영됩니다. |
|
||||
|
||||
`POST /mcp/{name}`의 동적 실행은 `visible` 및 `register` 값으로 차단하지 않습니다. 따라서 직접 호출을 막아야 하는 Tool은 네트워크 경계와 별도 인증·인가 정책으로 보호해야 합니다.
|
||||
|
||||
### 현재 Tool 선언 현황
|
||||
|
||||
`dap-was-oth`에는 실제 `@McpFunction` 선언이 17개 있습니다. 도메인은 다음과 같습니다.
|
||||
|
||||
| 도메인 | 예시 Tool 이름 | 내용 |
|
||||
|---|---|---|
|
||||
| `cmm` | `oth.cmm.claim.search`, `oth.cmm.customer.detail`, `oth.cmm.meta.table` | 공통·고객·계약·청구·메타 기능 |
|
||||
| `smp` | `oth.smp.weather.inquiry`, `oth.smp.exchange-rate.inquiry` | 샘플·조회 기능 |
|
||||
| `sol` | `oth.sol.request.list`, `oth.sol.request.detail` | SOL 요청 조회 |
|
||||
|
||||
`dap-was-oth`에는 `categoryKey = "oth"`인 `Onnba3011UseCase`도 있으나, 현재 `@McpFunction` 선언은 없습니다. `dap-was-sms`도 `@McpTool(routingType = "EAI", categoryKey = "notification")`은 선언되어 있지만, `SmsToolUseCase`/구현체에 `@McpFunction`이 없습니다. 따라서 현 상태에서 두 영역은 스캐너, `/tool-manifest`, MCP SDK에 노출되는 호출 가능 Tool을 만들지 않습니다. MCP Tool로 제공하려면 각 계약 메서드에 `@McpFunction`을 선언해야 합니다.
|
||||
|
||||
## Tool 개발 방식
|
||||
|
||||
Tool 그룹은 인터페이스에 `@McpTool`, Agent가 호출하는 메서드는 `@McpFunction`을 선언합니다. `@McpTool`은 Spring `@Component` 별칭이므로 Tool 인터페이스와 구현체는 Spring Bean으로 구성되어야 합니다.
|
||||
|
||||
```java
|
||||
@McpTool(routingType = "MCI", categoryKey = "claim")
|
||||
public interface ClaimInquiryUseCase {
|
||||
|
||||
@McpFunction(
|
||||
name = "oth.claim.inquiry.detail",
|
||||
displayName = "청구 상세 조회",
|
||||
description = "청구 번호로 청구 상세를 조회합니다.",
|
||||
mappingId = "CLM00000001",
|
||||
readOnlyHint = true
|
||||
)
|
||||
ClaimInquiryResponse inquire(ClaimInquiryRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
구현체에는 업무 흐름만 두고, Tool DTO와 레거시 인터페이스 DTO의 변환은 Converter에 둡니다.
|
||||
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
class ClaimInquiryUseCaseImpl implements ClaimInquiryUseCase {
|
||||
private final ClaimInquiryConverter converter;
|
||||
private final MciClaimClient client;
|
||||
|
||||
@Override
|
||||
public ClaimInquiryResponse inquire(ClaimInquiryRequest request) {
|
||||
ClaimMciRequest legacyRequest = converter.toMciRequest(request);
|
||||
ClaimMciResponse legacyResponse = client.call(legacyRequest);
|
||||
return converter.toResponse(legacyResponse);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`@McpFunction.name`은 소문자 점 표기 형식으로 작성합니다. 현재 선언은 `oth.cmm.claim.search`, `oth.smp.weather.inquiry`처럼 `{pod}.{domain}.{service}.{action}` 패턴을 사용합니다. `validateMcpToolNames` Gradle 작업은 모든 Tool 모듈을 대상으로 이름 형식과 중복을 검사하며, 패키징 빌드 전에 실행됩니다.
|
||||
|
||||
## Input/Output Schema
|
||||
|
||||
입력 Schema는 다음 우선순위로 결정됩니다.
|
||||
|
||||
1. `inputSchemaResource`에 지정한 classpath JSON Schema
|
||||
2. `inputSchema`에 인라인으로 지정한 JSON Schema
|
||||
3. 요청 DTO의 `@McpValidation`을 이용한 자동 생성 Schema
|
||||
|
||||
출력 검증은 선택 사항입니다. 다음 중 하나가 있을 때만 반환값을 검증합니다.
|
||||
|
||||
1. `outputSchemaResource`
|
||||
2. `outputSchema`
|
||||
3. 반환 DTO의 `@McpOutputSchema`와 `@McpValidation`
|
||||
|
||||
복잡한 Schema 리소스는 Tool 모듈에 둡니다. 현재 OTH의 청구 검색 예제는 다음 리소스를 사용합니다.
|
||||
|
||||
```text
|
||||
dap-was-oth/src/main/resources/tool-schemas/cmm/
|
||||
├─ claim-search-resource-input-schema.json
|
||||
└─ claim-search-resource-output-schema.json
|
||||
```
|
||||
|
||||
입력 검증에는 JSON Schema Draft 7이 사용됩니다. 출력 Schema 검증에 실패하면 `500 INVALID_TOOL_RESPONSE`을 반환합니다.
|
||||
|
||||
## 로컬 실행
|
||||
|
||||
### 사전 조건
|
||||
|
||||
- JDK 21
|
||||
- Docker (Redis 또는 MCI mock을 사용할 경우)
|
||||
- Gradle Wrapper 사용 권장
|
||||
|
||||
로컬 프로필은 기본값이며, 두 Pod 모두 H2 메모리 DB와 P6Spy를 설정합니다. Pod URL은 `AXHUB_TOOL_URL` 환경 변수로 설정하며, 지정하지 않으면 해당 `server.port`의 localhost 주소를 사용합니다.
|
||||
|
||||
```powershell
|
||||
# 필수: Redis 기동 (캐시 및 세션 처리용)
|
||||
$env:ACTIVE_PROFILE = 'local'
|
||||
docker compose up -d redis
|
||||
|
||||
# OTH Tool Pod 실행
|
||||
$env:SPRING_PROFILES_ACTIVE = 'local'
|
||||
$env:AXHUB_TOOL_URL = 'http://localhost:8084'
|
||||
.\gradlew.bat :dap-was-oth:bootRun
|
||||
|
||||
# SMS Tool Pod 실행 (별도 PowerShell)
|
||||
$env:SPRING_PROFILES_ACTIVE = 'local'
|
||||
$env:AXHUB_TOOL_URL = 'http://localhost:8082'
|
||||
.\gradlew.bat :dap-was-sms:bootRun
|
||||
```
|
||||
|
||||
실행 후 OTH Pod에서 다음 URL로 현재 스캔된 메타데이터와 Manifest를 확인할 수 있습니다.
|
||||
|
||||
```text
|
||||
http://localhost:8084/mcp/api/v1/tools/local
|
||||
http://localhost:8084/tool-manifest
|
||||
http://localhost:8084/tool-test-console.html
|
||||
```
|
||||
|
||||
`tool-test-console.html`은 공통 라이브러리의 정적 리소스입니다. `/tool-manifest`에서 Tool과 입력 Schema를 읽어 요청 JSON을 만들고, 현재 Pod의 `/mcp/{toolName}`으로 호출합니다. 저장한 테스트 케이스는 브라우저 `localStorage`에 보관됩니다.
|
||||
|
||||
## 테스트와 빌드
|
||||
|
||||
```powershell
|
||||
# 전체 테스트
|
||||
.\gradlew.bat test
|
||||
|
||||
# 공통 라이브러리 테스트
|
||||
.\gradlew.bat :dap-was-lib:test
|
||||
|
||||
# OTH Tool 테스트
|
||||
.\gradlew.bat :dap-was-oth:test
|
||||
|
||||
# Tool 이름 규칙 및 중복 검증
|
||||
.\gradlew.bat validateMcpToolNames
|
||||
|
||||
# 패키징 전 전체 빌드
|
||||
.\gradlew.bat clean build
|
||||
```
|
||||
|
||||
테스트는 공통 MCP Schema/Manifest/Header 처리, Glow MCI 파서, Tool 이름 검증과 OTH의 청구·SOL·MCI 변환을 다룹니다. SMS 모듈에는 현재 별도 테스트 소스가 없습니다.
|
||||
|
||||
## Docker Compose
|
||||
|
||||
현재 Compose 서비스와 호스트 포트는 다음과 같습니다.
|
||||
|
||||
| 서비스 | 컨테이너 포트 | 호스트 포트 |
|
||||
|---|---:|---:|
|
||||
| `redis` | 6379 | 6379 |
|
||||
| `was-sms` | 8082 | 8282 |
|
||||
| `was-oth` | 8084 | 8284 |
|
||||
|
||||
Compose의 Pod URL은 컨테이너 DNS 이름을 사용합니다.
|
||||
|
||||
```text
|
||||
was-sms: http://was-sms:8082
|
||||
was-oth: http://was-oth:8084
|
||||
```
|
||||
|
||||
### Docker 컨테이너 기동
|
||||
|
||||
별도의 CI/CD 러너나 외부 의존성(MCI Mock 등) 없이 독립적으로 실행 가능하도록 구성되어 있습니다. `docker-compose.yml`을 통해 Redis 및 각 Pod 컨테이너를 구동할 수 있습니다.
|
||||
|
||||
|
||||
## 설정
|
||||
|
||||
| 설정 | 위치/환경 변수 | 설명 |
|
||||
|---|---|---|
|
||||
| Pod 포트 | `server.port` 또는 `PORT` | SMS 8082, OTH 8084 |
|
||||
| Pod 외부 URL | `AXHUB_TOOL_URL` | 스캐너가 Tool endpoint를 만들 때 사용 |
|
||||
| MCP namespace | `mcp.namespace` | Tool 이름 앞에 `{namespace}_`를 붙임 |
|
||||
| Manifest bundle | `mcp.manifest.bundle-id` | SMS는 `tool-sms`, OTH는 `tool-oth` |
|
||||
| Manifest 이름 접두사 | `mcp.manifest.name-prefix` | 지정 시 모든 Manifest Tool 이름이 이 접두사로 시작해야 함 |
|
||||
| 활성 프로필 | `SPRING_PROFILES_ACTIVE` | 기본값 `local`, 선택값 `dev` |
|
||||
|
||||
`mcp.security.tenant-domains` 설정은 각 Pod의 YAML에 존재하지만, 현재 `McpProperties`와 `BusinessToolController`에는 이를 이용해 호출을 차단하는 로직이 없습니다. 문서상 권한 기능으로 간주하지 말고, 운영 노출 시 별도 인증·인가 계층을 적용해야 합니다.
|
||||
|
||||
## 보안과 운영 주의사항
|
||||
|
||||
- `BusinessToolController`는 요청 파라미터와 결과를 로그로 남깁니다. Tool 입력·응답에는 주민번호, 계좌번호, 전화번호, 인증값 등 민감정보를 포함하지 않도록 설계하고 공통 마스킹 적용 여부를 검토해야 합니다.
|
||||
- `employee-id` 헤더는 Controller가 수신하지만 현재 실행 로직에서 사용하지 않습니다. 이 헤더만으로 인증·인가가 수행된다고 가정하면 안 됩니다.
|
||||
- `mcp.security.tenant-domains`, `requiresApproval`, `register`는 현재 독립 WAS에서 실행 차단 정책을 구현하지 않습니다.
|
||||
- 외부 MCI/EAI 대상은 local/dev 설정과 실제 네트워크 정책을 별도로 점검해야 합니다.
|
||||
|
||||
## 참고 소스
|
||||
|
||||
| 주제 | 위치 |
|
||||
|---|---|
|
||||
| REST 실행 및 로컬 목록 | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/presentation/BusinessToolController.java` |
|
||||
| Manifest API | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/presentation/ToolManifestController.java` |
|
||||
| MCP Streamable HTTP | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolMcpServerConfiguration.java` |
|
||||
| MCP Tool 동기화 | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolPodMcpToolSynchronizer.java` |
|
||||
| Tool 스캔 | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/LocalToolScanner.java` |
|
||||
| Tool 어노테이션 | `dap-was-lib/src/main/java/io/shinhanlife/dap/lib/annotation/McpTool.java`, `McpFunction.java` |
|
||||
| OTH 업무 Tool | `dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/` |
|
||||
| SMS Tool | `dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/` |
|
||||
| 컨테이너 구성 | `docker-compose.yml`, `dap-was-oth/Dockerfile`, `dap-was-sms/Dockerfile` |
|
||||
113
build.gradle
Normal file
113
build.gradle
Normal file
@@ -0,0 +1,113 @@
|
||||
// 루트 Gradle 설정: 모든 Gateway/Tool Pod 모듈이 공유하는 빌드 기준을 정의합니다.
|
||||
plugins {
|
||||
// Java 컴파일, 테스트, JAR 생성 기능을 제공합니다.
|
||||
id 'java'
|
||||
|
||||
// 하위 실행 모듈에서 bootRun/bootJar를 사용하기 위한 Spring Boot 플러그인입니다.
|
||||
// 루트 프로젝트에는 적용하지 않으므로 apply false를 사용합니다.
|
||||
id 'org.springframework.boot' version '3.5.11' apply false
|
||||
|
||||
// Spring Boot / Spring AI BOM에 정의된 라이브러리 버전을 일관되게 적용합니다.
|
||||
id 'io.spring.dependency-management' version '1.1.6' apply false
|
||||
}
|
||||
|
||||
// 모든 모듈이 공유하는 Maven 식별자입니다.
|
||||
allprojects {
|
||||
group = 'io.shinhanlife'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
}
|
||||
|
||||
// dap-gateway, dap-was-lib, dap-was-oth, dap-was-sms에 공통 적용합니다.
|
||||
subprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
java {
|
||||
// 프로젝트 표준 Java 버전입니다.
|
||||
sourceCompatibility = '21'
|
||||
}
|
||||
|
||||
repositories {
|
||||
// 현재 공개 정식 라이브러리 저장소입니다.
|
||||
// 폐쇄망 적용 시 사내 Nexus Proxy URL로 교체합니다.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
// Spring Boot 3.5.11과 호환되는 Spring/Jackson/Tomcat 등의 버전을 관리합니다.
|
||||
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
|
||||
|
||||
// Boot 3.5.11과 호환되는 Spring AI 계층은 1.1.8로 유지합니다.
|
||||
mavenBom 'org.springframework.ai:spring-ai-bom:1.1.8'
|
||||
|
||||
// MCP Java SDK만 2.0.0으로 올립니다. Spring AI 2.x 전체 BOM은 Boot 4 기반이므로 사용하지 않습니다.
|
||||
mavenBom 'io.modelcontextprotocol.sdk:mcp-bom:2.0.0'
|
||||
|
||||
// MCP SDK 2.0의 Jackson 2 전송 모듈이 요구하는 호환 버전입니다.
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.20.1'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Lombok은 컴파일 시 getter/builder 등 반복 코드를 생성하며 실행 JAR에는 포함하지 않습니다.
|
||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
||||
testCompileOnly 'org.projectlombok:lombok:1.18.32'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.32'
|
||||
|
||||
// Tool DTO와 MCI 요청/응답 객체 간 Converter 구현체를 컴파일 시 자동 생성합니다.
|
||||
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
|
||||
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
|
||||
|
||||
// 모든 모듈의 JUnit 5 기반 테스트 공통 의존성입니다.
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
// 리플렉션/MCP Schema 생성 시 메서드 파라미터명을 사용할 수 있도록 보존합니다.
|
||||
options.compilerArgs << '-parameters'
|
||||
|
||||
// MapStruct 구현체를 Spring Bean으로 생성해 생성자 주입으로 사용할 수 있게 합니다.
|
||||
options.compilerArgs << '-Amapstruct.defaultComponentModel=spring'
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
// JUnit 5 테스트 플랫폼을 사용합니다.
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
// Tool 이름 중복 검사 프로그램이 포함된 공통 라이브러리 모듈입니다.
|
||||
def toolCoreProject = project(':dap-was-lib')
|
||||
|
||||
// 전체 Tool Pod의 @McpTool(name) 중복을 배포 산출물 생성 전에 차단합니다.
|
||||
tasks.register('validateMcpToolNames', JavaExec) {
|
||||
group = 'verification'
|
||||
description = 'Checks duplicate @McpTool names across all Tool modules before packaging.'
|
||||
|
||||
// 검사 Runner를 실행하기 전에 dap-was-lib 클래스를 먼저 컴파일합니다.
|
||||
dependsOn toolCoreProject.tasks.named('classes')
|
||||
classpath = toolCoreProject.sourceSets.main.runtimeClasspath
|
||||
mainClass.set('io.shinhanlife.dap.lib.validation.McpToolNameValidationRunner')
|
||||
args rootProject.projectDir.absolutePath
|
||||
}
|
||||
|
||||
tasks.register('validateToolSchemaV17', JavaExec) {
|
||||
group = 'verification'
|
||||
description = 'Validates BC-DAB-STD-003 V17 definitions for every @McpTool.'
|
||||
dependsOn toolCoreProject.tasks.named('classes')
|
||||
classpath = toolCoreProject.sourceSets.main.runtimeClasspath
|
||||
mainClass.set('io.shinhanlife.dap.lib.validation.ToolSchemaV17ValidationRunner')
|
||||
args rootProject.projectDir.absolutePath
|
||||
}
|
||||
|
||||
subprojects {
|
||||
// 배포용 Spring Boot JAR 생성 전에 Tool 이름 중복 검증을 강제합니다.
|
||||
tasks.matching { it.name == 'bootJar' }.configureEach {
|
||||
dependsOn rootProject.tasks.named('validateMcpToolNames')
|
||||
dependsOn rootProject.tasks.named('validateToolSchemaV17')
|
||||
}
|
||||
}
|
||||
8
dap-was-cus/Dockerfile
Normal file
8
dap-was-cus/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM eclipse-temurin:21-jre-alpine
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ=Asia/Seoul
|
||||
COPY dap-was-cus/build/libs/*-SNAPSHOT.jar app.jar
|
||||
EXPOSE 8084
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
|
||||
10
dap-was-cus/build.gradle
Normal file
10
dap-was-cus/build.gradle
Normal file
@@ -0,0 +1,10 @@
|
||||
plugins {
|
||||
// OTH Tool Pod를 독립 실행 가능한 Spring Boot JAR로 생성합니다.
|
||||
id 'org.springframework.boot'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// MCP Server, Tool 공통 처리, MCI/EAI 연동 기반은 dap-was-lib에서 상속합니다.
|
||||
implementation project(':dap-was-lib')
|
||||
implementation 'org.apache.poi:poi-ooxml:5.3.0'
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.shinhanlife.dap.mcc.biz.crm.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springaicommunity.mcp.annotation.McpToolParam;
|
||||
|
||||
@Data
|
||||
public class CrmToolRequest {
|
||||
@McpToolParam(description = "업무 대상 식별자", required = false)
|
||||
private String subjectId;
|
||||
|
||||
@McpToolParam(description = "고객 식별자", required = false)
|
||||
private String customerId;
|
||||
|
||||
@McpToolParam(description = "검색어 또는 처리 내용", required = false)
|
||||
private String content;
|
||||
|
||||
@McpToolParam(description = "상태, 유형, 등급 또는 처리 값", required = false)
|
||||
private String value;
|
||||
|
||||
@McpToolParam(description = "담당자 식별자", required = false)
|
||||
private String assigneeId;
|
||||
|
||||
@McpToolParam(description = "조회 시작일(YYYY-MM-DD)", required = false)
|
||||
private String startDate;
|
||||
|
||||
@McpToolParam(description = "조회 종료일 또는 처리 예정일(YYYY-MM-DD)", required = false)
|
||||
private String endDate;
|
||||
|
||||
@McpToolParam(description = "페이지 번호", required = false)
|
||||
private Integer page;
|
||||
|
||||
@McpToolParam(description = "페이지 크기", required = false)
|
||||
private Integer size;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.shinhanlife.dap.mcc.biz.crm.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CrmToolResponse {
|
||||
private String toolName;
|
||||
private String category;
|
||||
private String referenceId;
|
||||
private String status;
|
||||
private String summary;
|
||||
private String processedAt;
|
||||
private List<String> details;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.shinhanlife.dap.mcc.biz.crm.usecase;
|
||||
|
||||
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
|
||||
import io.shinhanlife.dap.mcc.biz.crm.dto.CrmToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.crm.dto.CrmToolResponse;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
|
||||
public interface CrmToolUseCase {
|
||||
@McpTool(name = "crm_customer_search", title = "고객 통합 조회", description = "고객 통합 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CUSTOMER_SEARCH")
|
||||
CrmToolResponse searchCustomers(CrmToolRequest request);
|
||||
@McpTool(name = "crm_customer_detail", title = "고객 상세 정보 조회", description = "고객 상세 정보 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CUSTOMER_DETAIL")
|
||||
CrmToolResponse getCustomerDetail(CrmToolRequest request);
|
||||
@McpTool(name = "crm_customer_create", title = "고객 정보 등록", description = "고객 정보 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_CUSTOMER_CREATE")
|
||||
CrmToolResponse createCustomer(CrmToolRequest request);
|
||||
@McpTool(name = "crm_customer_update", title = "고객 정보 수정", description = "고객 정보 수정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_CUSTOMER_UPDATE")
|
||||
CrmToolResponse updateCustomer(CrmToolRequest request);
|
||||
@McpTool(name = "crm_customer_duplicate_check", title = "고객 중복 여부 확인", description = "고객 중복 여부 확인 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CUSTOMER_DUPLICATE_CHECK")
|
||||
CrmToolResponse checkDuplicateCustomer(CrmToolRequest request);
|
||||
@McpTool(name = "crm_consultation_history", title = "고객 상담 이력 조회", description = "고객 상담 이력 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CONSULTATION_HISTORY")
|
||||
CrmToolResponse getConsultationHistory(CrmToolRequest request);
|
||||
@McpTool(name = "crm_consultation_register", title = "고객 상담 이력 등록", description = "고객 상담 이력 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_CONSULTATION_REGISTER")
|
||||
CrmToolResponse registerConsultation(CrmToolRequest request);
|
||||
@McpTool(name = "crm_contact_history", title = "고객 접촉 이력 조회", description = "고객 접촉 이력 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CONTACT_HISTORY")
|
||||
CrmToolResponse getContactHistory(CrmToolRequest request);
|
||||
@McpTool(name = "crm_contact_register", title = "고객 접촉 이력 등록", description = "고객 접촉 이력 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_CONTACT_REGISTER")
|
||||
CrmToolResponse registerContact(CrmToolRequest request);
|
||||
@McpTool(name = "crm_grade_detail", title = "고객 등급 조회", description = "고객 등급 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_GRADE_DETAIL")
|
||||
CrmToolResponse getCustomerGrade(CrmToolRequest request);
|
||||
@McpTool(name = "crm_grade_change", title = "고객 등급 변경", description = "고객 등급 변경 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_GRADE_CHANGE")
|
||||
CrmToolResponse changeCustomerGrade(CrmToolRequest request);
|
||||
@McpTool(name = "crm_segment_detail", title = "고객 세그먼트 조회", description = "고객 세그먼트 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_SEGMENT_DETAIL")
|
||||
CrmToolResponse getCustomerSegment(CrmToolRequest request);
|
||||
@McpTool(name = "crm_tag_manage", title = "고객 태그 관리", description = "고객 태그 관리 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_TAG_MANAGE")
|
||||
CrmToolResponse manageCustomerTags(CrmToolRequest request);
|
||||
@McpTool(name = "crm_consent_detail", title = "고객 동의 정보 조회", description = "고객 동의 정보 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_CONSENT_DETAIL")
|
||||
CrmToolResponse getCustomerConsent(CrmToolRequest request);
|
||||
@McpTool(name = "crm_consent_change", title = "고객 동의 정보 변경", description = "고객 동의 정보 변경 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_CONSENT_CHANGE")
|
||||
CrmToolResponse changeCustomerConsent(CrmToolRequest request);
|
||||
@McpTool(name = "crm_owner_assign", title = "고객 담당자 배정", description = "고객 담당자 배정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "crm", mappingId = "DIRECT_CRM_OWNER_ASSIGN")
|
||||
CrmToolResponse assignCustomerOwner(CrmToolRequest request);
|
||||
@McpTool(name = "crm_activity_status", title = "고객 활동 현황 조회", description = "고객 활동 현황 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "crm", mappingId = "DIRECT_CRM_ACTIVITY_STATUS")
|
||||
CrmToolResponse getCustomerActivityStatus(CrmToolRequest request);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.shinhanlife.dap.mcc.biz.crm.usecase.impl;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.crm.dto.CrmToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.crm.dto.CrmToolResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.crm.usecase.CrmToolUseCase;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CrmToolUseCaseImpl implements CrmToolUseCase {
|
||||
@Override
|
||||
public CrmToolResponse searchCustomers(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_customer_search", "고객 통합 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getCustomerDetail(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_customer_detail", "고객 상세 정보 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse createCustomer(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_customer_create", "고객 정보 등록");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse updateCustomer(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_customer_update", "고객 정보 수정");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse checkDuplicateCustomer(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_customer_duplicate_check", "고객 중복 여부 확인");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getConsultationHistory(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_consultation_history", "고객 상담 이력 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse registerConsultation(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_consultation_register", "고객 상담 이력 등록");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getContactHistory(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_contact_history", "고객 접촉 이력 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse registerContact(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_contact_register", "고객 접촉 이력 등록");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getCustomerGrade(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_grade_detail", "고객 등급 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse changeCustomerGrade(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_grade_change", "고객 등급 변경");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getCustomerSegment(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_segment_detail", "고객 세그먼트 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse manageCustomerTags(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_tag_manage", "고객 태그 관리");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getCustomerConsent(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_consent_detail", "고객 동의 정보 조회");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse changeCustomerConsent(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_consent_change", "고객 동의 정보 변경");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse assignCustomerOwner(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_owner_assign", "고객 담당자 배정");
|
||||
}
|
||||
@Override
|
||||
public CrmToolResponse getCustomerActivityStatus(CrmToolRequest request) {
|
||||
return mockResponse(request, "crm_activity_status", "고객 활동 현황 조회");
|
||||
}
|
||||
private CrmToolResponse mockResponse(CrmToolRequest request, String toolName, String title) {
|
||||
CrmToolResponse response = new CrmToolResponse();
|
||||
response.setToolName(toolName);
|
||||
response.setCategory("CRM");
|
||||
response.setReferenceId(request != null && hasText(request.getSubjectId()) ? request.getSubjectId() : "CRM-000001");
|
||||
response.setStatus("정상");
|
||||
response.setSummary(title + " 처리 결과");
|
||||
response.setProcessedAt(LocalDateTime.now().toString());
|
||||
response.setDetails(List.of(title + " 모의 상세 정보", "외부 시스템을 변경하지 않는 샘플 응답"));
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.shinhanlife.dap.mcc.biz.voc.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springaicommunity.mcp.annotation.McpToolParam;
|
||||
|
||||
@Data
|
||||
public class VocToolRequest {
|
||||
@McpToolParam(description = "업무 대상 식별자", required = false)
|
||||
private String subjectId;
|
||||
|
||||
@McpToolParam(description = "고객 식별자", required = false)
|
||||
private String customerId;
|
||||
|
||||
@McpToolParam(description = "검색어 또는 처리 내용", required = false)
|
||||
private String content;
|
||||
|
||||
@McpToolParam(description = "상태, 유형, 등급 또는 처리 값", required = false)
|
||||
private String value;
|
||||
|
||||
@McpToolParam(description = "담당자 식별자", required = false)
|
||||
private String assigneeId;
|
||||
|
||||
@McpToolParam(description = "조회 시작일(YYYY-MM-DD)", required = false)
|
||||
private String startDate;
|
||||
|
||||
@McpToolParam(description = "조회 종료일 또는 처리 예정일(YYYY-MM-DD)", required = false)
|
||||
private String endDate;
|
||||
|
||||
@McpToolParam(description = "페이지 번호", required = false)
|
||||
private Integer page;
|
||||
|
||||
@McpToolParam(description = "페이지 크기", required = false)
|
||||
private Integer size;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.shinhanlife.dap.mcc.biz.voc.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class VocToolResponse {
|
||||
private String toolName;
|
||||
private String category;
|
||||
private String referenceId;
|
||||
private String status;
|
||||
private String summary;
|
||||
private String processedAt;
|
||||
private List<String> details;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.shinhanlife.dap.mcc.biz.voc.usecase;
|
||||
|
||||
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
|
||||
import io.shinhanlife.dap.mcc.biz.voc.dto.VocToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.voc.dto.VocToolResponse;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
|
||||
public interface VocToolUseCase {
|
||||
@McpTool(name = "voc_register", title = "VOC 접수 등록", description = "VOC 접수 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_REGISTER")
|
||||
VocToolResponse registerVoc(VocToolRequest request);
|
||||
@McpTool(name = "voc_detail", title = "VOC 상세 조회", description = "VOC 상세 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_DETAIL")
|
||||
VocToolResponse getVocDetail(VocToolRequest request);
|
||||
@McpTool(name = "voc_search", title = "VOC 목록 검색", description = "VOC 목록 검색 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_SEARCH")
|
||||
VocToolResponse searchVocs(VocToolRequest request);
|
||||
@McpTool(name = "voc_update", title = "VOC 내용 수정", description = "VOC 내용 수정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_UPDATE")
|
||||
VocToolResponse updateVoc(VocToolRequest request);
|
||||
@McpTool(name = "voc_assign", title = "VOC 담당자 배정", description = "VOC 담당자 배정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_ASSIGN")
|
||||
VocToolResponse assignVocOwner(VocToolRequest request);
|
||||
@McpTool(name = "voc_change_status", title = "VOC 처리 상태 변경", description = "VOC 처리 상태 변경 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_CHANGE_STATUS")
|
||||
VocToolResponse changeVocStatus(VocToolRequest request);
|
||||
@McpTool(name = "voc_register_result", title = "VOC 처리 결과 등록", description = "VOC 처리 결과 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_REGISTER_RESULT")
|
||||
VocToolResponse registerVocResult(VocToolRequest request);
|
||||
@McpTool(name = "voc_send_reply", title = "VOC 답변 발송", description = "VOC 답변 발송 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_SEND_REPLY")
|
||||
VocToolResponse sendVocReply(VocToolRequest request);
|
||||
@McpTool(name = "voc_transfer", title = "VOC 이관 처리", description = "VOC 이관 처리 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_TRANSFER")
|
||||
VocToolResponse transferVoc(VocToolRequest request);
|
||||
@McpTool(name = "voc_set_priority", title = "VOC 우선순위 설정", description = "VOC 우선순위 설정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_SET_PRIORITY")
|
||||
VocToolResponse setVocPriority(VocToolRequest request);
|
||||
@McpTool(name = "voc_classify_type", title = "VOC 유형 분류", description = "VOC 유형 분류 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_CLASSIFY_TYPE")
|
||||
VocToolResponse classifyVocType(VocToolRequest request);
|
||||
@McpTool(name = "voc_attachments", title = "VOC 첨부파일 조회", description = "VOC 첨부파일 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_ATTACHMENTS")
|
||||
VocToolResponse getVocAttachments(VocToolRequest request);
|
||||
@McpTool(name = "voc_customer_history", title = "고객별 VOC 이력 조회", description = "고객별 VOC 이력 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_CUSTOMER_HISTORY")
|
||||
VocToolResponse getCustomerVocHistory(VocToolRequest request);
|
||||
@McpTool(name = "voc_detect_duplicate", title = "중복 VOC 탐지", description = "중복 VOC 탐지 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_DETECT_DUPLICATE")
|
||||
VocToolResponse detectDuplicateVoc(VocToolRequest request);
|
||||
@McpTool(name = "voc_urgent_list", title = "긴급 VOC 목록 조회", description = "긴급 VOC 목록 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_URGENT_LIST")
|
||||
VocToolResponse getUrgentVocs(VocToolRequest request);
|
||||
@McpTool(name = "voc_extend_due_date", title = "VOC 처리 기한 연장", description = "VOC 처리 기한 연장 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "voc", mappingId = "DIRECT_VOC_EXTEND_DUE_DATE")
|
||||
VocToolResponse extendVocDueDate(VocToolRequest request);
|
||||
@McpTool(name = "voc_statistics", title = "VOC 통계 조회", description = "VOC 통계 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "voc", mappingId = "DIRECT_VOC_STATISTICS")
|
||||
VocToolResponse getVocStatistics(VocToolRequest request);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.shinhanlife.dap.mcc.biz.voc.usecase.impl;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.voc.dto.VocToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.voc.dto.VocToolResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.voc.usecase.VocToolUseCase;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class VocToolUseCaseImpl implements VocToolUseCase {
|
||||
@Override
|
||||
public VocToolResponse registerVoc(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_register", "VOC 접수 등록");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse getVocDetail(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_detail", "VOC 상세 조회");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse searchVocs(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_search", "VOC 목록 검색");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse updateVoc(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_update", "VOC 내용 수정");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse assignVocOwner(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_assign", "VOC 담당자 배정");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse changeVocStatus(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_change_status", "VOC 처리 상태 변경");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse registerVocResult(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_register_result", "VOC 처리 결과 등록");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse sendVocReply(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_send_reply", "VOC 답변 발송");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse transferVoc(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_transfer", "VOC 이관 처리");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse setVocPriority(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_set_priority", "VOC 우선순위 설정");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse classifyVocType(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_classify_type", "VOC 유형 분류");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse getVocAttachments(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_attachments", "VOC 첨부파일 조회");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse getCustomerVocHistory(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_customer_history", "고객별 VOC 이력 조회");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse detectDuplicateVoc(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_detect_duplicate", "중복 VOC 탐지");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse getUrgentVocs(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_urgent_list", "긴급 VOC 목록 조회");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse extendVocDueDate(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_extend_due_date", "VOC 처리 기한 연장");
|
||||
}
|
||||
@Override
|
||||
public VocToolResponse getVocStatistics(VocToolRequest request) {
|
||||
return mockResponse(request, "voc_statistics", "VOC 통계 조회");
|
||||
}
|
||||
private VocToolResponse mockResponse(VocToolRequest request, String toolName, String title) {
|
||||
VocToolResponse response = new VocToolResponse();
|
||||
response.setToolName(toolName);
|
||||
response.setCategory("VOC");
|
||||
response.setReferenceId(request != null && hasText(request.getSubjectId()) ? request.getSubjectId() : "VOC-000001");
|
||||
response.setStatus("정상");
|
||||
response.setSummary(title + " 처리 결과");
|
||||
response.setProcessedAt(LocalDateTime.now().toString());
|
||||
response.setDetails(List.of(title + " 모의 상세 정보", "외부 시스템을 변경하지 않는 샘플 응답"));
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.shinhanlife.dap.mcc.biz.wcm.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springaicommunity.mcp.annotation.McpToolParam;
|
||||
|
||||
@Data
|
||||
public class WcmToolRequest {
|
||||
@McpToolParam(description = "업무 대상 식별자", required = false)
|
||||
private String subjectId;
|
||||
|
||||
@McpToolParam(description = "고객 식별자", required = false)
|
||||
private String customerId;
|
||||
|
||||
@McpToolParam(description = "검색어 또는 처리 내용", required = false)
|
||||
private String content;
|
||||
|
||||
@McpToolParam(description = "상태, 유형, 등급 또는 처리 값", required = false)
|
||||
private String value;
|
||||
|
||||
@McpToolParam(description = "담당자 식별자", required = false)
|
||||
private String assigneeId;
|
||||
|
||||
@McpToolParam(description = "조회 시작일(YYYY-MM-DD)", required = false)
|
||||
private String startDate;
|
||||
|
||||
@McpToolParam(description = "조회 종료일 또는 처리 예정일(YYYY-MM-DD)", required = false)
|
||||
private String endDate;
|
||||
|
||||
@McpToolParam(description = "페이지 번호", required = false)
|
||||
private Integer page;
|
||||
|
||||
@McpToolParam(description = "페이지 크기", required = false)
|
||||
private Integer size;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.shinhanlife.dap.mcc.biz.wcm.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WcmToolResponse {
|
||||
private String toolName;
|
||||
private String category;
|
||||
private String referenceId;
|
||||
private String status;
|
||||
private String summary;
|
||||
private String processedAt;
|
||||
private List<String> details;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.shinhanlife.dap.mcc.biz.wcm.usecase;
|
||||
|
||||
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
|
||||
import io.shinhanlife.dap.mcc.biz.wcm.dto.WcmToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.wcm.dto.WcmToolResponse;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
|
||||
public interface WcmToolUseCase {
|
||||
@McpTool(name = "wcm_content_list", title = "웹 콘텐츠 목록 조회", description = "웹 콘텐츠 목록 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_LIST")
|
||||
WcmToolResponse getContentList(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_detail", title = "웹 콘텐츠 상세 조회", description = "웹 콘텐츠 상세 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_DETAIL")
|
||||
WcmToolResponse getContentDetail(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_create", title = "웹 콘텐츠 등록", description = "웹 콘텐츠 등록 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_CREATE")
|
||||
WcmToolResponse createContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_update", title = "웹 콘텐츠 수정", description = "웹 콘텐츠 수정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_UPDATE")
|
||||
WcmToolResponse updateContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_delete", title = "웹 콘텐츠 삭제", description = "웹 콘텐츠 삭제 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_DELETE")
|
||||
WcmToolResponse deleteContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_copy", title = "웹 콘텐츠 복사", description = "웹 콘텐츠 복사 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_COPY")
|
||||
WcmToolResponse copyContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_preview", title = "웹 콘텐츠 미리보기", description = "웹 콘텐츠 미리보기 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_PREVIEW")
|
||||
WcmToolResponse previewContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_publish", title = "웹 콘텐츠 게시", description = "웹 콘텐츠 게시 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_PUBLISH")
|
||||
WcmToolResponse publishContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_unpublish", title = "웹 콘텐츠 게시 중지", description = "웹 콘텐츠 게시 중지 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_UNPUBLISH")
|
||||
WcmToolResponse unpublishContent(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_schedule_publish", title = "웹 콘텐츠 예약 게시", description = "웹 콘텐츠 예약 게시 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_SCHEDULE_PUBLISH")
|
||||
WcmToolResponse scheduleContentPublish(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_request_approval", title = "웹 콘텐츠 승인 요청", description = "웹 콘텐츠 승인 요청 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_REQUEST_APPROVAL")
|
||||
WcmToolResponse requestContentApproval(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_review_approval", title = "웹 콘텐츠 승인·반려", description = "웹 콘텐츠 승인·반려 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_REVIEW_APPROVAL")
|
||||
WcmToolResponse reviewContentApproval(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_version_history", title = "웹 콘텐츠 버전 이력 조회", description = "웹 콘텐츠 버전 이력 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_VERSION_HISTORY")
|
||||
WcmToolResponse getContentVersionHistory(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_content_restore_version", title = "웹 콘텐츠 이전 버전 복원", description = "웹 콘텐츠 이전 버전 복원 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_CONTENT_RESTORE_VERSION")
|
||||
WcmToolResponse restoreContentVersion(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_metadata_detail", title = "콘텐츠 메타데이터 조회", description = "콘텐츠 메타데이터 조회 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = false, categoryKey = "wcm", mappingId = "DIRECT_WCM_METADATA_DETAIL")
|
||||
WcmToolResponse getContentMetadata(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_metadata_upsert", title = "콘텐츠 메타데이터 등록·수정", description = "콘텐츠 메타데이터 등록·수정 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_METADATA_UPSERT")
|
||||
WcmToolResponse upsertContentMetadata(WcmToolRequest request);
|
||||
@McpTool(name = "wcm_taxonomy_manage", title = "콘텐츠 카테고리·태그 관리", description = "콘텐츠 카테고리·태그 관리 기능을 안전한 모의 데이터로 제공합니다.")
|
||||
@GrowToolHint(requiresApproval = true, categoryKey = "wcm", mappingId = "DIRECT_WCM_TAXONOMY_MANAGE")
|
||||
WcmToolResponse manageContentTaxonomy(WcmToolRequest request);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.shinhanlife.dap.mcc.biz.wcm.usecase.impl;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.wcm.dto.WcmToolRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.wcm.dto.WcmToolResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.wcm.usecase.WcmToolUseCase;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WcmToolUseCaseImpl implements WcmToolUseCase {
|
||||
@Override
|
||||
public WcmToolResponse getContentList(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_list", "웹 콘텐츠 목록 조회");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse getContentDetail(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_detail", "웹 콘텐츠 상세 조회");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse createContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_create", "웹 콘텐츠 등록");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse updateContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_update", "웹 콘텐츠 수정");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse deleteContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_delete", "웹 콘텐츠 삭제");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse copyContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_copy", "웹 콘텐츠 복사");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse previewContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_preview", "웹 콘텐츠 미리보기");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse publishContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_publish", "웹 콘텐츠 게시");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse unpublishContent(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_unpublish", "웹 콘텐츠 게시 중지");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse scheduleContentPublish(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_schedule_publish", "웹 콘텐츠 예약 게시");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse requestContentApproval(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_request_approval", "웹 콘텐츠 승인 요청");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse reviewContentApproval(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_review_approval", "웹 콘텐츠 승인·반려");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse getContentVersionHistory(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_version_history", "웹 콘텐츠 버전 이력 조회");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse restoreContentVersion(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_content_restore_version", "웹 콘텐츠 이전 버전 복원");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse getContentMetadata(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_metadata_detail", "콘텐츠 메타데이터 조회");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse upsertContentMetadata(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_metadata_upsert", "콘텐츠 메타데이터 등록·수정");
|
||||
}
|
||||
@Override
|
||||
public WcmToolResponse manageContentTaxonomy(WcmToolRequest request) {
|
||||
return mockResponse(request, "wcm_taxonomy_manage", "콘텐츠 카테고리·태그 관리");
|
||||
}
|
||||
private WcmToolResponse mockResponse(WcmToolRequest request, String toolName, String title) {
|
||||
WcmToolResponse response = new WcmToolResponse();
|
||||
response.setToolName(toolName);
|
||||
response.setCategory("WCMS");
|
||||
response.setReferenceId(request != null && hasText(request.getSubjectId()) ? request.getSubjectId() : "WCMS-000001");
|
||||
response.setStatus("정상");
|
||||
response.setSummary(title + " 처리 결과");
|
||||
response.setProcessedAt(LocalDateTime.now().toString());
|
||||
response.setDetails(List.of(title + " 모의 상세 정보", "외부 시스템을 변경하지 않는 샘플 응답"));
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.shinhanlife.dap.mcc.cus;
|
||||
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.mcc.cus
|
||||
* @className DapWasCusApplication
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
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.dap.lib.mcp.ToolMcpServerConfiguration;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib"})
|
||||
@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib"})
|
||||
@EnableCaching
|
||||
@Import(ToolMcpServerConfiguration.class)
|
||||
public class DapWasCusApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DapWasCusApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
package io.shinhanlife.dap.mcc.presentation;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFColor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* MCI DTO 클래스를 조회하고 인터페이스 설계서 형식의 엑셀 파일을 생성한다.
|
||||
* 외부 템플릿 파일에 의존하지 않고 Apache POI로 양식과 데이터를 모두 만든다.
|
||||
*/
|
||||
@RestController
|
||||
public class DtoExcelDownloadController {
|
||||
|
||||
private static final int FIRST_FIELD_ROW = 12;
|
||||
private static final int TEMPLATE_LAST_ROW = 35;
|
||||
private static final int COLUMN_COUNT = 20;
|
||||
private static final MediaType XLSX_MEDIA_TYPE = MediaType.parseMediaType(
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
private static final String MCI_BASE_PACKAGE = "io.shinhanlife.dap.mcc.infra.itrf.mci";
|
||||
private static final String INVALID_DTO_MESSAGE =
|
||||
"dto의 내용이 엑셀파일 양식에 맞지않습니다 파일을 확인해주세요";
|
||||
private static final Pattern VARIANT_SUFFIX = Pattern.compile("_[IO]$");
|
||||
|
||||
private final Map<String, String> dtoClasses;
|
||||
|
||||
public DtoExcelDownloadController() {
|
||||
this.dtoClasses = scanDtoClasses();
|
||||
}
|
||||
|
||||
@GetMapping("/dto-download/options")
|
||||
public List<String> options() {
|
||||
// DTO는 항상 _I/_O 한 쌍으로 존재하므로 접미사를 제거한 이름 단위로 묶어 화면에 제공한다.
|
||||
Set<String> baseNames = new TreeSet<>();
|
||||
for (String simpleName : dtoClasses.keySet()) {
|
||||
baseNames.add(VARIANT_SUFFIX.matcher(simpleName).replaceFirst(""));
|
||||
}
|
||||
return List.copyOf(baseNames);
|
||||
}
|
||||
|
||||
@GetMapping("/dto-download/{dtoName}")
|
||||
public ResponseEntity<byte[]> download(@PathVariable String dtoName) throws IOException {
|
||||
// 스캔되지 않은 이름을 받아 임의 클래스를 조회하지 못하도록 제한한다.
|
||||
String className = dtoClasses.get(dtoName);
|
||||
if (className == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
byte[] workbook = createWorkbook(dtoName, className);
|
||||
String fileName = dtoName + ".xlsx";
|
||||
return ResponseEntity.ok()
|
||||
.contentType(XLSX_MEDIA_TYPE)
|
||||
.contentLength(workbook.length)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
ContentDisposition.attachment().filename(fileName).build().toString())
|
||||
.body(workbook);
|
||||
}
|
||||
|
||||
@ExceptionHandler(DtoFormatException.class)
|
||||
public ResponseEntity<String> handleInvalidDto() {
|
||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||
.contentType(MediaType.parseMediaType("text/plain;charset=UTF-8"))
|
||||
.body(INVALID_DTO_MESSAGE);
|
||||
}
|
||||
|
||||
private byte[] createWorkbook(String dtoName, String className) throws IOException {
|
||||
// 요청마다 새 워크북을 생성하므로 여러 사용자의 다운로드가 서로 영향을 주지 않는다.
|
||||
try (XSSFWorkbook workbook = createTemplateWorkbook();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
setText(sheet, 2, 2, dtoName);
|
||||
setText(sheet, 3, 2, dtoName);
|
||||
|
||||
List<FieldRow> fields;
|
||||
try {
|
||||
fields = describeFields(Class.forName(className));
|
||||
} catch (ReflectiveOperationException error) {
|
||||
throw new IOException("DTO class could not be inspected: " + className, error);
|
||||
}
|
||||
writeFields(sheet, fields);
|
||||
workbook.write(output);
|
||||
return output.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private XSSFWorkbook createTemplateWorkbook() {
|
||||
// 기준 문서의 시트명, 열 너비, 병합, 색상과 테두리를 코드로 재현한다.
|
||||
XSSFWorkbook workbook = new XSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("대내");
|
||||
sheet.setDisplayGridlines(false);
|
||||
sheet.createFreezePane(0, 12);
|
||||
sheet.getPrintSetup().setLandscape(true);
|
||||
sheet.setRepeatingRows(new CellRangeAddress(11, 11, -1, -1));
|
||||
|
||||
double[] widths = {4.44, 8, 23.22, 23.22, 10, 14, 18, 11, 9, 7.44,
|
||||
8, 9.55, 9, 10.55, 11.44, 9, 13, 10.55, 14, 30};
|
||||
for (int column = 0; column < widths.length; column++) {
|
||||
sheet.setColumnWidth(column, (int) (widths[column] * 256));
|
||||
}
|
||||
|
||||
CellStyle titleStyle = style(workbook, "000000", "FFFFFF", true, (short) 14,
|
||||
HorizontalAlignment.CENTER, false);
|
||||
CellStyle sectionStyle = style(workbook, "F2F2F2", "000000", true, (short) 10,
|
||||
HorizontalAlignment.CENTER, false);
|
||||
CellStyle labelStyle = borderedStyle(workbook, "F2F2F2", true, HorizontalAlignment.CENTER);
|
||||
CellStyle inputStyle = borderedStyle(workbook, "C6D9F1", false, HorizontalAlignment.LEFT);
|
||||
CellStyle requiredStyle = borderedStyle(workbook, "C6D9F1", false, HorizontalAlignment.LEFT);
|
||||
CellStyle autoStyle = borderedStyle(workbook, "F2DCDB", false, HorizontalAlignment.LEFT);
|
||||
CellStyle userStyle = borderedStyle(workbook, "FFFFFF", false, HorizontalAlignment.LEFT);
|
||||
CellStyle headerStyle = borderedStyle(workbook, "D9D9D9", true, HorizontalAlignment.CENTER);
|
||||
headerStyle.setWrapText(true);
|
||||
CellStyle whiteDataStyle = borderedStyle(workbook, "FFFFFF", false, HorizontalAlignment.CENTER);
|
||||
CellStyle blueDataStyle = borderedStyle(workbook, "C6D9F1", false, HorizontalAlignment.CENTER);
|
||||
CellStyle pinkDataStyle = borderedStyle(workbook, "F2DCDB", false, HorizontalAlignment.CENTER);
|
||||
|
||||
createStyledRow(sheet, 0, 25.5f, titleStyle);
|
||||
merge(sheet, "A1:T1");
|
||||
setText(sheet, 0, 0, "인터페이스 설계서(대내)");
|
||||
|
||||
createStyledRow(sheet, 1, 18f, sectionStyle);
|
||||
merge(sheet, "A2:T2");
|
||||
setText(sheet, 1, 0, "기본정보");
|
||||
|
||||
String[] labels = {"코드", "한글명", "영문명", "암호화", "유형", "레코드구분자", "필드구분자"};
|
||||
for (int index = 0; index < labels.length; index++) {
|
||||
int rowIndex = index + 2;
|
||||
Row row = sheet.createRow(rowIndex);
|
||||
cell(row, 1, labelStyle).setCellValue(labels[index]);
|
||||
cell(row, 2, inputStyle);
|
||||
cell(row, 3, inputStyle);
|
||||
merge(sheet, "C" + (rowIndex + 1) + ":D" + (rowIndex + 1));
|
||||
}
|
||||
setText(sheet, 6, 2, "json");
|
||||
sheet.getRow(7).setHeightInPoints(24);
|
||||
sheet.getRow(8).setHeightInPoints(24);
|
||||
|
||||
for (int rowIndex = 3; rowIndex <= 5; rowIndex++) {
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
CellStyle legendStyle = rowIndex == 3 ? requiredStyle : rowIndex == 4 ? autoStyle : userStyle;
|
||||
cell(row, 5, legendStyle);
|
||||
cell(row, 6, legendStyle);
|
||||
merge(sheet, "F" + (rowIndex + 1) + ":G" + (rowIndex + 1));
|
||||
}
|
||||
setText(sheet, 3, 7, "필수입력");
|
||||
setText(sheet, 4, 7, "필드자동채우기(메타시스템 연동시)");
|
||||
setText(sheet, 5, 7, "사용자입력(필요시)");
|
||||
|
||||
createStyledRow(sheet, 10, 18f, sectionStyle);
|
||||
merge(sheet, "A11:T11");
|
||||
setText(sheet, 10, 0, "필드정보");
|
||||
|
||||
String[] headers = {"NO", "Level", "한글명", "부모식별자(한글명)", "끝수여부", "영문명",
|
||||
"부모식별자(영문명)", "데이터유형", "필드길이", "SCALE", "기본값", "정렬기준",
|
||||
"채움문자", "암호화방식", "메타체크여부", "한글여부", "소수점포함여부",
|
||||
"마스킹여부", "마스킹패턴코드", "비고"};
|
||||
Row header = sheet.createRow(11);
|
||||
header.setHeightInPoints(30);
|
||||
for (int column = 0; column < headers.length; column++) {
|
||||
cell(header, column, headerStyle).setCellValue(headers[column]);
|
||||
}
|
||||
|
||||
for (int rowIndex = FIRST_FIELD_ROW; rowIndex <= TEMPLATE_LAST_ROW; rowIndex++) {
|
||||
Row row = sheet.createRow(rowIndex);
|
||||
row.setHeightInPoints(15.75f);
|
||||
for (int column = 0; column < COLUMN_COUNT; column++) {
|
||||
CellStyle dataStyle;
|
||||
if (column == 0 || column == 4 || (column >= 14 && column <= 16) || column == 19) {
|
||||
dataStyle = whiteDataStyle;
|
||||
} else if (column >= 1 && column <= 3) {
|
||||
dataStyle = blueDataStyle;
|
||||
} else {
|
||||
dataStyle = pinkDataStyle;
|
||||
}
|
||||
cell(row, column, dataStyle);
|
||||
}
|
||||
}
|
||||
return workbook;
|
||||
}
|
||||
|
||||
private CellStyle style(XSSFWorkbook workbook, String fillColor, String fontColor,
|
||||
boolean bold, short fontSize, HorizontalAlignment alignment,
|
||||
boolean bordered) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setAlignment(alignment);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setFillForegroundColor(new XSSFColor(java.awt.Color.decode("#" + fillColor), null));
|
||||
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
Font font = workbook.createFont();
|
||||
font.setFontName("맑은 고딕");
|
||||
font.setFontHeightInPoints(fontSize);
|
||||
font.setBold(bold);
|
||||
font.setColor("FFFFFF".equals(fontColor) ? IndexedColors.WHITE.getIndex() : IndexedColors.BLACK.getIndex());
|
||||
style.setFont(font);
|
||||
if (bordered) setBorders(style);
|
||||
return style;
|
||||
}
|
||||
|
||||
private CellStyle borderedStyle(XSSFWorkbook workbook, String fillColor,
|
||||
boolean bold, HorizontalAlignment alignment) {
|
||||
return style(workbook, fillColor, "000000", bold, (short) 9, alignment, true);
|
||||
}
|
||||
|
||||
private void setBorders(CellStyle style) {
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
}
|
||||
|
||||
private void createStyledRow(Sheet sheet, int rowIndex, float height, CellStyle style) {
|
||||
Row row = sheet.createRow(rowIndex);
|
||||
row.setHeightInPoints(height);
|
||||
for (int column = 0; column < COLUMN_COUNT; column++) cell(row, column, style);
|
||||
}
|
||||
|
||||
private Cell cell(Row row, int column, CellStyle style) {
|
||||
Cell cell = row.createCell(column);
|
||||
cell.setCellStyle(style);
|
||||
return cell;
|
||||
}
|
||||
|
||||
private void merge(Sheet sheet, String range) {
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf(range));
|
||||
}
|
||||
|
||||
private void writeFields(Sheet sheet, List<FieldRow> fields) {
|
||||
// 기본 24행을 유지하고 필드가 더 많으면 마지막 행의 서식을 복제해 확장한다.
|
||||
int requiredRows = Math.max(fields.size(), TEMPLATE_LAST_ROW - FIRST_FIELD_ROW + 1);
|
||||
for (int offset = 0; offset < requiredRows; offset++) {
|
||||
int rowIndex = FIRST_FIELD_ROW + offset;
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
if (row == null) {
|
||||
row = cloneTemplateRow(sheet, rowIndex);
|
||||
}
|
||||
clearRowValues(row);
|
||||
setNumber(row, 0, offset + 1);
|
||||
if (offset < fields.size()) {
|
||||
FieldRow field = fields.get(offset);
|
||||
setNumber(row, 1, field.level());
|
||||
setText(row, 2, field.description());
|
||||
setText(row, 3, field.parentDescription());
|
||||
setText(row, 5, field.name());
|
||||
setText(row, 6, field.parentName());
|
||||
setText(row, 7, field.dataType());
|
||||
if (field.length() > 0) {
|
||||
setNumber(row, 8, field.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Row cloneTemplateRow(Sheet sheet, int rowIndex) {
|
||||
Row source = sheet.getRow(TEMPLATE_LAST_ROW);
|
||||
Row target = sheet.createRow(rowIndex);
|
||||
target.setHeight(source.getHeight());
|
||||
for (int column = 0; column < COLUMN_COUNT; column++) {
|
||||
Cell sourceCell = source.getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
Cell targetCell = target.createCell(column);
|
||||
CellStyle style = sourceCell.getCellStyle();
|
||||
targetCell.setCellStyle(style);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private void clearRowValues(Row row) {
|
||||
for (int column = 0; column < COLUMN_COUNT; column++) {
|
||||
Cell cell = row.getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
cell.setBlank();
|
||||
}
|
||||
}
|
||||
|
||||
private List<FieldRow> describeFields(Class<?> rootClass) {
|
||||
List<FieldRow> output = new ArrayList<>();
|
||||
appendFields(rootClass, 1, "", "", output);
|
||||
return output;
|
||||
}
|
||||
|
||||
private void appendFields(Class<?> type, int level, String parentName,
|
||||
String parentDescription, List<FieldRow> output) {
|
||||
// 중첩 DTO와 List 요소 타입을 재귀적으로 펼쳐 Level 및 부모 식별자를 계산한다.
|
||||
List<Field> fields = new ArrayList<>(List.of(type.getDeclaredFields()));
|
||||
fields.removeIf(field -> field.isSynthetic());
|
||||
fields.sort(Comparator.comparingInt(this::fieldOrder));
|
||||
for (Field field : fields) {
|
||||
Annotation metadata = telegramMetadata(field);
|
||||
// 한글명, 순서, 길이를 알 수 없는 DTO는 설계서 양식으로 변환할 수 없다.
|
||||
if (metadata == null) {
|
||||
throw new DtoFormatException();
|
||||
}
|
||||
String description = annotationString(metadata, "description", field.getName());
|
||||
int length = annotationInt(metadata, "length", 0);
|
||||
Class<?> nestedType = nestedType(field);
|
||||
String dataType = annotationString(metadata, "type", simpleDataType(field));
|
||||
output.add(new FieldRow(level, description, parentDescription, field.getName(),
|
||||
parentName, dataType, length));
|
||||
if (nestedType != null && nestedType != type) {
|
||||
appendFields(nestedType, level + 1, field.getName(), description, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int fieldOrder(Field field) {
|
||||
return annotationInt(telegramMetadata(field), "order", Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private Annotation telegramMetadata(Field field) {
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
String annotationName = annotation.annotationType().getSimpleName();
|
||||
if (annotationName.equals("GlowTrgmField")
|
||||
|| annotationName.equals("GlowMciFieldInfo")) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String annotationString(Annotation annotation, String methodName, String fallback) {
|
||||
Object value = annotationValue(annotation, methodName);
|
||||
return value instanceof String text && !text.isBlank() ? text : fallback;
|
||||
}
|
||||
|
||||
private int annotationInt(Annotation annotation, String methodName, int fallback) {
|
||||
Object value = annotationValue(annotation, methodName);
|
||||
return value instanceof Number number ? number.intValue() : fallback;
|
||||
}
|
||||
|
||||
private Object annotationValue(Annotation annotation, String methodName) {
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Method method = annotation.annotationType().getMethod(methodName);
|
||||
return method.invoke(annotation);
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> nestedType(Field field) {
|
||||
Class<?> type = field.getType();
|
||||
if (List.class.isAssignableFrom(type) && field.getGenericType() instanceof ParameterizedType generic) {
|
||||
Type argument = generic.getActualTypeArguments()[0];
|
||||
if (argument instanceof Class<?> itemType && isDtoType(itemType)) {
|
||||
return itemType;
|
||||
}
|
||||
}
|
||||
return isDtoType(type) ? type : null;
|
||||
}
|
||||
|
||||
private boolean isDtoType(Class<?> type) {
|
||||
return !type.isPrimitive()
|
||||
&& !type.getName().startsWith("java.")
|
||||
&& !type.isEnum();
|
||||
}
|
||||
|
||||
private String simpleDataType(Field field) {
|
||||
if (List.class.isAssignableFrom(field.getType())) {
|
||||
return "List";
|
||||
}
|
||||
return field.getType().getSimpleName();
|
||||
}
|
||||
|
||||
private void setText(Sheet sheet, int row, int column, String value) {
|
||||
setText(sheet.getRow(row), column, value);
|
||||
}
|
||||
|
||||
private void setText(Row row, int column, String value) {
|
||||
row.getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellValue(value == null ? "" : value);
|
||||
}
|
||||
|
||||
private void setNumber(Row row, int column, int value) {
|
||||
row.getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellValue(value);
|
||||
}
|
||||
|
||||
private Map<String, String> scanDtoClasses() {
|
||||
// itrf.mci 하위의 모든 io 패키지를 검색하므로 신규 DTO 추가 시 하드코딩이 필요 없다.
|
||||
ClassPathScanningCandidateComponentProvider scanner =
|
||||
new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new RegexPatternTypeFilter(
|
||||
Pattern.compile(".*\\.itrf\\.mci\\..*\\.io\\.[^.]+$")));
|
||||
|
||||
Map<String, String> classes = new TreeMap<>();
|
||||
scanner.findCandidateComponents(MCI_BASE_PACKAGE).forEach(candidate -> {
|
||||
String className = candidate.getBeanClassName();
|
||||
if (className == null || className.contains("$")) {
|
||||
return;
|
||||
}
|
||||
String simpleName = className.substring(className.lastIndexOf('.') + 1);
|
||||
String previous = classes.putIfAbsent(simpleName, className);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("Duplicate DTO class name: " + simpleName);
|
||||
}
|
||||
});
|
||||
return Map.copyOf(classes);
|
||||
}
|
||||
|
||||
private record FieldRow(int level, String description, String parentDescription,
|
||||
String name, String parentName, String dataType, int length) {
|
||||
}
|
||||
|
||||
private static final class DtoFormatException extends RuntimeException {
|
||||
}
|
||||
}
|
||||
15
dap-was-cus/src/main/resources/application-dev.yml
Normal file
15
dap-was-cus/src/main/resources/application-dev.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
# OCI 클라우드 개발 환경 전용 설정
|
||||
server:
|
||||
port: ${PORT:8084}
|
||||
|
||||
axhub:
|
||||
gateway:
|
||||
url: https://axhubmcp.devjun.net
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
import:
|
||||
- classpath:glow/application-glow.yml
|
||||
- classpath:glow/application-glow-dev.yml
|
||||
32
dap-was-cus/src/main/resources/application-local.yml
Normal file
32
dap-was-cus/src/main/resources/application-local.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
# Local 환경 전용 설정 (H2 메모리 DB 등)
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: local
|
||||
import:
|
||||
- classpath:glow/application-glow.yml
|
||||
- classpath:glow/application-glow-local.yml
|
||||
datasource:
|
||||
url: jdbc:p6spy:h2:mem:testdb;DB_CLOSE_DELAY=-1;
|
||||
driverClassName: com.p6spy.engine.spy.P6SpyDriver
|
||||
username: sa
|
||||
password: password
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
|
||||
mcp:
|
||||
security:
|
||||
tenant-domains:
|
||||
mcp-client-1: CUSTOMER,COMMON
|
||||
mcp-client-2: ALL
|
||||
|
||||
axhub:
|
||||
gateway:
|
||||
url: http://localhost:8081
|
||||
tool:
|
||||
url: ${AXHUB_TOOL_URL:http://localhost:${server.port}}
|
||||
|
||||
sol:
|
||||
req-detail:
|
||||
mock-enabled: true
|
||||
16
dap-was-cus/src/main/resources/application-prod.yml
Normal file
16
dap-was-cus/src/main/resources/application-prod.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
server:
|
||||
port: ${PORT:8084}
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
import:
|
||||
- classpath:glow/application-glow.yml
|
||||
- classpath:glow/application-glow-prod.yml
|
||||
|
||||
axhub:
|
||||
gateway:
|
||||
url: ${AXHUB_GATEWAY_URL}
|
||||
tool:
|
||||
url: ${AXHUB_TOOL_URL}
|
||||
16
dap-was-cus/src/main/resources/application-test.yml
Normal file
16
dap-was-cus/src/main/resources/application-test.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
server:
|
||||
port: ${PORT:8084}
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: test
|
||||
import:
|
||||
- classpath:glow/application-glow.yml
|
||||
- classpath:glow/application-glow-test.yml
|
||||
|
||||
axhub:
|
||||
gateway:
|
||||
url: ${AXHUB_GATEWAY_URL}
|
||||
tool:
|
||||
url: ${AXHUB_TOOL_URL}
|
||||
19
dap-was-cus/src/main/resources/application.yml
Normal file
19
dap-was-cus/src/main/resources/application.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
server:
|
||||
port: 8084
|
||||
spring:
|
||||
application:
|
||||
name: dap-was-cus
|
||||
profiles:
|
||||
active: local
|
||||
logging:
|
||||
level:
|
||||
org.apache.kafka: ERROR
|
||||
mcp:
|
||||
namespace: ""
|
||||
manifest:
|
||||
bundle-id: was-cus
|
||||
# Set the AA-assigned prefix before MCP pull activation (for example: cus.).
|
||||
name-prefix: ""
|
||||
security:
|
||||
tenant-domains:
|
||||
TESTER-DEV: ALL
|
||||
41
dap-was-cus/src/main/resources/logback-spring.xml
Normal file
41
dap-was-cus/src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!-- 1. 로그 패턴 설정 (MDC traceId 포함) -->
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n" />
|
||||
|
||||
<!-- 2. 콘솔(Console) 출력 설정 (로컬 개발용) -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 3. 파일(File) 출력 설정 (서버 운영용) -->
|
||||
<!-- Logback에서 시스템 Hostname을 가져오기 위한 설정 -->
|
||||
<property name="HOSTNAME" value="${HOSTNAME}" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>/swlog/dap-was-cus/A01/${HOSTNAME}_A01.log</file> <!-- 현재 로그가 쌓이는 파일 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!-- 매일 자정에 날짜를 붙여서 지난 로그를 분리 저장 -->
|
||||
<fileNamePattern>/swlog/dap-was-cus/A01/${HOSTNAME}_A01_%d{yyyyMMdd}.%i.log</fileNamePattern>
|
||||
<!-- 개별 로그 파일 크기를 100MB로 제한하고, 전체 보관 일수는 30일, 총 로그 누적 용량은 1GB로 제한 -->
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>1GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 4. 기본 로깅 레벨 설정 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
|
||||
<!-- 5. 우리 프로젝트 패키지는 디버그 레벨까지 상세히 보기 -->
|
||||
<logger name="io.shinhanlife" level="DEBUG" />
|
||||
</configuration>
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"resultCode" : "SUCCESS",
|
||||
"data" : "[{\"date\":\"2024-01-05\",\"message\":\"안내 내용\"}]"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"resultCode" : "SUCCESS",
|
||||
"claimId" : "CLM20230001"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_activity_status
|
||||
display_name: 고객 활동 현황 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 활동 현황 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 활동 현황 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 활동 현황 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 활동 현황 조회 해줘", "고객 활동 현황 조회 결과를 알려줘", "고객 활동 현황 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_consent_change
|
||||
display_name: 고객 동의 정보 변경
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 동의 정보 변경 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 동의 정보 변경 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 동의 정보 변경 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 동의 정보 변경 해줘", "고객 동의 정보 변경 결과를 알려줘", "고객 동의 정보 변경 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_consent_detail
|
||||
display_name: 고객 동의 정보 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 동의 정보 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 동의 정보 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 동의 정보 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 동의 정보 조회 해줘", "고객 동의 정보 조회 결과를 알려줘", "고객 동의 정보 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_consultation_history
|
||||
display_name: 고객 상담 이력 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 상담 이력 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 상담 이력 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 상담 이력 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 상담 이력 조회 해줘", "고객 상담 이력 조회 결과를 알려줘", "고객 상담 이력 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_consultation_register
|
||||
display_name: 고객 상담 이력 등록
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 상담 이력 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 상담 이력 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 상담 이력 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 상담 이력 등록 해줘", "고객 상담 이력 등록 결과를 알려줘", "고객 상담 이력 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_contact_history
|
||||
display_name: 고객 접촉 이력 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 접촉 이력 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 접촉 이력 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 접촉 이력 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 접촉 이력 조회 해줘", "고객 접촉 이력 조회 결과를 알려줘", "고객 접촉 이력 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_contact_register
|
||||
display_name: 고객 접촉 이력 등록
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 접촉 이력 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 접촉 이력 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 접촉 이력 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 접촉 이력 등록 해줘", "고객 접촉 이력 등록 결과를 알려줘", "고객 접촉 이력 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_customer_create
|
||||
display_name: 고객 정보 등록
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 정보 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 정보 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 정보 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 정보 등록 해줘", "고객 정보 등록 결과를 알려줘", "고객 정보 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_customer_detail
|
||||
display_name: 고객 상세 정보 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 상세 정보 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 상세 정보 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 상세 정보 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 상세 정보 조회 해줘", "고객 상세 정보 조회 결과를 알려줘", "고객 상세 정보 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_customer_duplicate_check
|
||||
display_name: 고객 중복 여부 확인
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 중복 여부 확인 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 중복 여부 확인 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 중복 여부 확인 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 중복 여부 확인 해줘", "고객 중복 여부 확인 결과를 알려줘", "고객 중복 여부 확인 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_customer_search
|
||||
display_name: 고객 통합 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 통합 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 통합 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 통합 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 통합 조회 해줘", "고객 통합 조회 결과를 알려줘", "고객 통합 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_customer_update
|
||||
display_name: 고객 정보 수정
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 정보 수정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 정보 수정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 정보 수정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 정보 수정 해줘", "고객 정보 수정 결과를 알려줘", "고객 정보 수정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_grade_change
|
||||
display_name: 고객 등급 변경
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 등급 변경 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 등급 변경 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 등급 변경 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 등급 변경 해줘", "고객 등급 변경 결과를 알려줘", "고객 등급 변경 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_grade_detail
|
||||
display_name: 고객 등급 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 등급 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 등급 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 등급 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 등급 조회 해줘", "고객 등급 조회 결과를 알려줘", "고객 등급 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_owner_assign
|
||||
display_name: 고객 담당자 배정
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 담당자 배정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 담당자 배정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 담당자 배정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 담당자 배정 해줘", "고객 담당자 배정 결과를 알려줘", "고객 담당자 배정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_segment_detail
|
||||
display_name: 고객 세그먼트 조회
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 세그먼트 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 세그먼트 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 세그먼트 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 세그먼트 조회 해줘", "고객 세그먼트 조회 결과를 알려줘", "고객 세그먼트 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: crm_tag_manage
|
||||
display_name: 고객 태그 관리
|
||||
version: 1.0.0
|
||||
category_key: crm
|
||||
description:
|
||||
function: 고객 태그 관리 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객 태그 관리 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객 태그 관리 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객 태그 관리 해줘", "고객 태그 관리 결과를 알려줘", "고객 태그 관리 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [crm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_assign
|
||||
display_name: VOC 담당자 배정
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 담당자 배정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 담당자 배정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 담당자 배정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 담당자 배정 해줘", "VOC 담당자 배정 결과를 알려줘", "VOC 담당자 배정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_attachments
|
||||
display_name: VOC 첨부파일 조회
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 첨부파일 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 첨부파일 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 첨부파일 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 첨부파일 조회 해줘", "VOC 첨부파일 조회 결과를 알려줘", "VOC 첨부파일 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_change_status
|
||||
display_name: VOC 처리 상태 변경
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 처리 상태 변경 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 처리 상태 변경 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 처리 상태 변경 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 처리 상태 변경 해줘", "VOC 처리 상태 변경 결과를 알려줘", "VOC 처리 상태 변경 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_classify_type
|
||||
display_name: VOC 유형 분류
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 유형 분류 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 유형 분류 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 유형 분류 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 유형 분류 해줘", "VOC 유형 분류 결과를 알려줘", "VOC 유형 분류 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_customer_history
|
||||
display_name: 고객별 VOC 이력 조회
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: 고객별 VOC 이력 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 고객별 VOC 이력 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 고객별 VOC 이력 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["고객별 VOC 이력 조회 해줘", "고객별 VOC 이력 조회 결과를 알려줘", "고객별 VOC 이력 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_detail
|
||||
display_name: VOC 상세 조회
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 상세 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 상세 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 상세 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 상세 조회 해줘", "VOC 상세 조회 결과를 알려줘", "VOC 상세 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_detect_duplicate
|
||||
display_name: 중복 VOC 탐지
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: 중복 VOC 탐지 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 중복 VOC 탐지 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 중복 VOC 탐지 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["중복 VOC 탐지 해줘", "중복 VOC 탐지 결과를 알려줘", "중복 VOC 탐지 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_extend_due_date
|
||||
display_name: VOC 처리 기한 연장
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 처리 기한 연장 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 처리 기한 연장 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 처리 기한 연장 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 처리 기한 연장 해줘", "VOC 처리 기한 연장 결과를 알려줘", "VOC 처리 기한 연장 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_register
|
||||
display_name: VOC 접수 등록
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 접수 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 접수 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 접수 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 접수 등록 해줘", "VOC 접수 등록 결과를 알려줘", "VOC 접수 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_register_result
|
||||
display_name: VOC 처리 결과 등록
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 처리 결과 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 처리 결과 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 처리 결과 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 처리 결과 등록 해줘", "VOC 처리 결과 등록 결과를 알려줘", "VOC 처리 결과 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_search
|
||||
display_name: VOC 목록 검색
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 목록 검색 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 목록 검색 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 목록 검색 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 목록 검색 해줘", "VOC 목록 검색 결과를 알려줘", "VOC 목록 검색 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_send_reply
|
||||
display_name: VOC 답변 발송
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 답변 발송 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 답변 발송 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 답변 발송 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 답변 발송 해줘", "VOC 답변 발송 결과를 알려줘", "VOC 답변 발송 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_set_priority
|
||||
display_name: VOC 우선순위 설정
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 우선순위 설정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 우선순위 설정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 우선순위 설정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 우선순위 설정 해줘", "VOC 우선순위 설정 결과를 알려줘", "VOC 우선순위 설정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_statistics
|
||||
display_name: VOC 통계 조회
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 통계 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 통계 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 통계 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 통계 조회 해줘", "VOC 통계 조회 결과를 알려줘", "VOC 통계 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_transfer
|
||||
display_name: VOC 이관 처리
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 이관 처리 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 이관 처리 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 이관 처리 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 이관 처리 해줘", "VOC 이관 처리 결과를 알려줘", "VOC 이관 처리 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_update
|
||||
display_name: VOC 내용 수정
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: VOC 내용 수정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 VOC 내용 수정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: VOC 내용 수정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["VOC 내용 수정 해줘", "VOC 내용 수정 결과를 알려줘", "VOC 내용 수정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: voc_urgent_list
|
||||
display_name: 긴급 VOC 목록 조회
|
||||
version: 1.0.0
|
||||
category_key: voc
|
||||
description:
|
||||
function: 긴급 VOC 목록 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 긴급 VOC 목록 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 긴급 VOC 목록 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["긴급 VOC 목록 조회 해줘", "긴급 VOC 목록 조회 결과를 알려줘", "긴급 VOC 목록 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [voc, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_copy
|
||||
display_name: 웹 콘텐츠 복사
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 복사 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 복사 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 복사 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 복사 해줘", "웹 콘텐츠 복사 결과를 알려줘", "웹 콘텐츠 복사 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_create
|
||||
display_name: 웹 콘텐츠 등록
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 등록 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 등록 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 등록 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 등록 해줘", "웹 콘텐츠 등록 결과를 알려줘", "웹 콘텐츠 등록 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: false
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_delete
|
||||
display_name: 웹 콘텐츠 삭제
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 삭제 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 삭제 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 삭제 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 삭제 해줘", "웹 콘텐츠 삭제 결과를 알려줘", "웹 콘텐츠 삭제 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: true
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_detail
|
||||
display_name: 웹 콘텐츠 상세 조회
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 상세 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 상세 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 상세 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 상세 조회 해줘", "웹 콘텐츠 상세 조회 결과를 알려줘", "웹 콘텐츠 상세 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_list
|
||||
display_name: 웹 콘텐츠 목록 조회
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 목록 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 목록 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 목록 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 목록 조회 해줘", "웹 콘텐츠 목록 조회 결과를 알려줘", "웹 콘텐츠 목록 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_preview
|
||||
display_name: 웹 콘텐츠 미리보기
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 미리보기 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 미리보기 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 미리보기 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 미리보기 해줘", "웹 콘텐츠 미리보기 결과를 알려줘", "웹 콘텐츠 미리보기 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_publish
|
||||
display_name: 웹 콘텐츠 게시
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 게시 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 게시 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 게시 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 게시 해줘", "웹 콘텐츠 게시 결과를 알려줘", "웹 콘텐츠 게시 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_request_approval
|
||||
display_name: 웹 콘텐츠 승인 요청
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 승인 요청 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 승인 요청 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 승인 요청 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 승인 요청 해줘", "웹 콘텐츠 승인 요청 결과를 알려줘", "웹 콘텐츠 승인 요청 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_restore_version
|
||||
display_name: 웹 콘텐츠 이전 버전 복원
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 이전 버전 복원 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 이전 버전 복원 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 이전 버전 복원 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 이전 버전 복원 해줘", "웹 콘텐츠 이전 버전 복원 결과를 알려줘", "웹 콘텐츠 이전 버전 복원 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_review_approval
|
||||
display_name: 웹 콘텐츠 승인·반려
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 승인·반려 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 승인·반려 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 승인·반려 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 승인·반려 해줘", "웹 콘텐츠 승인·반려 결과를 알려줘", "웹 콘텐츠 승인·반려 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_schedule_publish
|
||||
display_name: 웹 콘텐츠 예약 게시
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 예약 게시 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 예약 게시 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 예약 게시 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 예약 게시 해줘", "웹 콘텐츠 예약 게시 결과를 알려줘", "웹 콘텐츠 예약 게시 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_unpublish
|
||||
display_name: 웹 콘텐츠 게시 중지
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 게시 중지 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 게시 중지 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 게시 중지 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 게시 중지 해줘", "웹 콘텐츠 게시 중지 결과를 알려줘", "웹 콘텐츠 게시 중지 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_update
|
||||
display_name: 웹 콘텐츠 수정
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 수정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 수정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 수정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 수정 해줘", "웹 콘텐츠 수정 결과를 알려줘", "웹 콘텐츠 수정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_content_version_history
|
||||
display_name: 웹 콘텐츠 버전 이력 조회
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 웹 콘텐츠 버전 이력 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 웹 콘텐츠 버전 이력 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 웹 콘텐츠 버전 이력 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["웹 콘텐츠 버전 이력 조회 해줘", "웹 콘텐츠 버전 이력 조회 결과를 알려줘", "웹 콘텐츠 버전 이력 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_metadata_detail
|
||||
display_name: 콘텐츠 메타데이터 조회
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 콘텐츠 메타데이터 조회 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 콘텐츠 메타데이터 조회 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 정보 변경이나 승인 처리가 필요한 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 조회 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 콘텐츠 메타데이터 조회 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["콘텐츠 메타데이터 조회 해줘", "콘텐츠 메타데이터 조회 결과를 알려줘", "콘텐츠 메타데이터 조회 기능을 실행해줘"]
|
||||
read_only: true
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 조회, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_metadata_upsert
|
||||
display_name: 콘텐츠 메타데이터 등록·수정
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 콘텐츠 메타데이터 등록·수정 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 콘텐츠 메타데이터 등록·수정 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 콘텐츠 메타데이터 등록·수정 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["콘텐츠 메타데이터 등록·수정 해줘", "콘텐츠 메타데이터 등록·수정 결과를 알려줘", "콘텐츠 메타데이터 등록·수정 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,30 @@
|
||||
name: wcm_taxonomy_manage
|
||||
display_name: 콘텐츠 카테고리·태그 관리
|
||||
version: 1.0.0
|
||||
category_key: wcm
|
||||
description:
|
||||
function: 콘텐츠 카테고리·태그 관리 기능을 수행합니다.
|
||||
when_to_use: 고객채널 업무에서 콘텐츠 카테고리·태그 관리 기능이 필요할 때 사용합니다.
|
||||
when_not_to_use: 필수 식별자와 변경 내용이 확인되지 않은 경우에는 사용하지 않습니다.
|
||||
io_limits: 입력 범위에 대한 모의 처리 결과만 반환하며 외부 시스템을 직접 변경하지 않습니다.
|
||||
display_description: 콘텐츠 카테고리·태그 관리 기능을 안전한 모의 데이터로 제공합니다.
|
||||
example_queries: ["콘텐츠 카테고리·태그 관리 해줘", "콘텐츠 카테고리·태그 관리 결과를 알려줘", "콘텐츠 카테고리·태그 관리 기능을 실행해줘"]
|
||||
read_only: false
|
||||
destructive: false
|
||||
idempotent: true
|
||||
parameters_schema:
|
||||
type: object
|
||||
properties:
|
||||
subjectId: {type: string, description: 업무 대상 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
customerId: {type: string, description: 고객 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
content: {type: string, description: 검색어 또는 처리 내용, maxLength: 2000}
|
||||
value: {type: string, description: 상태·유형·등급 또는 처리 값, maxLength: 100}
|
||||
assigneeId: {type: string, description: 담당자 식별자, pattern: "^[A-Za-z0-9_-]{3,40}$"}
|
||||
startDate: {type: string, description: 조회 시작일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
endDate: {type: string, description: 조회 종료일 또는 처리 예정일, pattern: "^\\d{4}-\\d{2}-\\d{2}$"}
|
||||
page: {type: integer, description: 페이지 번호, minimum: 0}
|
||||
size: {type: integer, description: 페이지 크기, minimum: 1, maximum: 100}
|
||||
additionalProperties: false
|
||||
tags: [wcm, 고객채널, 처리, mock]
|
||||
required_env_keys: []
|
||||
owner_org: MCP_TOOL
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.shinhanlife.dap.mcc.presentation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
class DtoExcelDownloadControllerTest {
|
||||
|
||||
private final DtoExcelDownloadController controller = new DtoExcelDownloadController();
|
||||
|
||||
@Test
|
||||
void downloadsBothOnild0320Variants() throws Exception {
|
||||
assertWorkbook("ONILD0320_I", "csNo");
|
||||
assertWorkbook("ONILD0320_O", "notiDt");
|
||||
}
|
||||
|
||||
private void assertWorkbook(String dtoName, String expectedField) throws Exception {
|
||||
ResponseEntity<byte[]> response = controller.download(dtoName);
|
||||
|
||||
assertThat(response.getStatusCode().is2xxSuccessful()).isTrue();
|
||||
assertThat(response.getBody()).isNotNull();
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(response.getBody()))) {
|
||||
assertThat(workbook.getSheetAt(0))
|
||||
.anySatisfy(row -> assertThat(row)
|
||||
.anySatisfy(cell -> assertThat(cell.toString()).isEqualTo(expectedField)));
|
||||
}
|
||||
}
|
||||
}
|
||||
60
dap-was-lib/build.gradle
Normal file
60
dap-was-lib/build.gradle
Normal file
@@ -0,0 +1,60 @@
|
||||
plugins {
|
||||
// Gateway와 모든 Tool Pod가 의존하는 공통 라이브러리 모듈입니다.
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// 공통 REST Controller, HTTP Client, 예외 처리 기반입니다.
|
||||
api 'org.springframework.boot:spring-boot-starter-web'
|
||||
|
||||
// Tool Request DTO의 Bean Validation을 지원합니다.
|
||||
api 'org.springframework.boot:spring-boot-starter-validation'
|
||||
|
||||
// Tool Manifest/Registry 캐시 및 Redis 기반 공통 기능을 제공합니다.
|
||||
api 'org.springframework.boot:spring-boot-starter-data-redis'
|
||||
|
||||
// Tool SLA, 로깅, 공통 Aspect를 적용합니다.
|
||||
api 'org.springframework.boot:spring-boot-starter-aop'
|
||||
|
||||
// MCI/DB 연동에 필요한 JDBC 공통 기능입니다.
|
||||
api 'org.springframework.boot:spring-boot-starter-jdbc'
|
||||
|
||||
// Tool 호출의 Circuit Breaker, Rate Limit, Retry 등 복원력 기능입니다.
|
||||
api 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
|
||||
api 'io.github.resilience4j:resilience4j-core:2.2.0'
|
||||
api 'io.github.resilience4j:resilience4j-circuitbreaker:2.2.0'
|
||||
api 'io.github.resilience4j:resilience4j-ratelimiter'
|
||||
api 'io.github.resilience4j:resilience4j-retry:2.2.0'
|
||||
|
||||
// MCI/업무 데이터 접근을 위한 MyBatis 지원입니다.
|
||||
api 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
|
||||
|
||||
// 현재 로컬 테스트 DB 및 SQL 로그 처리에 사용합니다.
|
||||
api 'com.h2database:h2'
|
||||
api 'p6spy:p6spy:3.9.1'
|
||||
|
||||
// Spring Data Redis가 사용하는 Redis Client를 공통 모듈에서 직접 참조합니다.
|
||||
api 'io.lettuce:lettuce-core:6.6.0.RELEASE'
|
||||
|
||||
// MCI XML 전문, JSON Tool Schema/Manifest 처리에 사용합니다.
|
||||
api 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml'
|
||||
api 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'
|
||||
api 'com.fasterxml.jackson.core:jackson-databind'
|
||||
// MCP Java SDK 2.0.0의 mcp-json-jackson2가 호출하는 Schema API와 반드시 맞춘다.
|
||||
// 3.x는 Schema.validate(JsonNode) 반환 규격이 달라 런타임 NoSuchMethodError가 발생한다.
|
||||
api 'com.networknt:json-schema-validator:2.0.0'
|
||||
|
||||
// Boot 3.5.11 위에서 MCP Java SDK 2.0.0의 Server/Client와 Servlet 전송 계층을 사용합니다.
|
||||
// Jackson 2 공급자를 명시해 Boot 3의 Jackson 계열과 맞춥니다.
|
||||
api 'io.modelcontextprotocol.sdk:mcp-core'
|
||||
api 'io.modelcontextprotocol.sdk:mcp-json-jackson2'
|
||||
|
||||
// Boot 3.5 호환 Spring AI 어노테이션 API를 유지합니다.
|
||||
api 'org.springaicommunity:mcp-annotations:0.9.0'
|
||||
|
||||
// 이벤트 기반 확장이 필요한 Tool의 공통 Kafka 연동 기능입니다.
|
||||
api 'org.springframework.kafka:spring-kafka:3.2.0'
|
||||
|
||||
// Tool Pod REST API 문서 및 Swagger UI를 제공합니다.
|
||||
api 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.shinhanlife.dap.lib.adapter.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.dto
|
||||
* @className ErrorDetail
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
public class ErrorDetail {
|
||||
private int code;
|
||||
private String message;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.shinhanlife.dap.lib.adapter.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.dto
|
||||
* @className JsonRpcRequest
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class JsonRpcRequest {
|
||||
private String jsonrpc;
|
||||
private String method;
|
||||
private Params params;
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.shinhanlife.dap.lib.adapter.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
// 2. 응답 DTO
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.dto
|
||||
* @className JsonRpcResponse
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonPropertyOrder({"jsonrpc", "result", "error", "id"})
|
||||
public class JsonRpcResponse {
|
||||
public String jsonrpc = "2.0";
|
||||
public Object result;
|
||||
public Object error;
|
||||
public String id;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.shinhanlife.dap.lib.adapter.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.dto
|
||||
* @className Params
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Params {
|
||||
private String routingType;
|
||||
private String name;
|
||||
private String interfaceId;
|
||||
private Map<String, Object> data;
|
||||
private List<Map<String, Object>> spec;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.shinhanlife.dap.lib.adapter.test;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Local HTTP mock server for scaffolded HTTP Tools.
|
||||
*
|
||||
* <p>Each Tool Pod returns the JSON generated under
|
||||
* {@code src/main/resources/mock-responses/{toolName}.json}. It is enabled only
|
||||
* when {@code axhub.mock.http.enabled=true}, which the HTTP Scaffold adds to local configuration.</p>
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnProperty(prefix = "axhub.mock.http", name = "enabled", havingValue = "true")
|
||||
@RequestMapping("/api")
|
||||
public class MockEimsHttpServer {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@PostMapping("/mock/http/{toolName:[a-z0-9_-]+}")
|
||||
public ResponseEntity<JsonNode> mockToolHttpResponse(
|
||||
@PathVariable String toolName,
|
||||
@RequestBody(required = false) JsonNode request) {
|
||||
ClassPathResource resource = new ClassPathResource("mock-responses/" + toolName + ".json");
|
||||
if (!resource.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
try {
|
||||
log.info("[MockEimsHttpServer] HTTP mock request. toolName={}, body={}", toolName, request);
|
||||
return ResponseEntity.ok(objectMapper.readTree(resource.getInputStream()));
|
||||
} catch (Exception e) {
|
||||
log.warn("[MockEimsHttpServer] Unable to read mock response. toolName={}", toolName, e);
|
||||
return ResponseEntity.internalServerError().build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/gateway")
|
||||
public ResponseEntity<?> mockEimsReceiver(
|
||||
@RequestHeader(value = "X-Trace-Id", required = false) String traceId,
|
||||
@RequestBody Map<String, Object> request) {
|
||||
String interfaceId = String.valueOf(request.getOrDefault("interfaceId", ""));
|
||||
log.info("[MockEimsHttpServer] Legacy gateway mock request. traceId={}, interfaceId={}", traceId, interfaceId);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"status", "404",
|
||||
"message", "MOCK data is not defined for interfaceId: " + interfaceId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.shinhanlife.dap.lib.adapter.util;
|
||||
|
||||
import ch.qos.logback.classic.pattern.MessageConverter;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
|
||||
/**
|
||||
* Logback 커스텀 컨버터
|
||||
* 모든 로그 메시지(%msg)가 파일이나 콘솔에 찍히기 직전에 이 클래스를 거쳐가게 됩니다.
|
||||
* 여기서 PiiMaskingUtils.mask()를 호출하여 PII(주민번호, 계좌번호 등)를 안전하게 별표(*) 처리합니다.
|
||||
*/
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.util
|
||||
* @className PiiMaskingLogbackConverter
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class PiiMaskingLogbackConverter extends MessageConverter {
|
||||
|
||||
@Override
|
||||
public String convert(ILoggingEvent event) {
|
||||
// 원본 로그 메시지를 가져옵니다.
|
||||
String originalMessage = super.convert(event);
|
||||
|
||||
// 정규식을 이용하여 개인정보가 포함되어 있으면 마스킹 처리하여 반환합니다.
|
||||
return PiiMaskingUtils.mask(originalMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package io.shinhanlife.dap.lib.adapter.util;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.adapter.util
|
||||
* @className PiiMaskingUtils
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class PiiMaskingUtils {
|
||||
|
||||
// 1. 주민등록번호 패턴 (ex: 900101-1234567 또는 9001011234567)
|
||||
private static final Pattern RRN_PATTERN = Pattern.compile("(\\d{6})[-]?([1-4]\\d{6})");
|
||||
|
||||
// 2. 휴대전화번호 패턴 (ex: 010-1234-5678)
|
||||
private static final Pattern PHONE_PATTERN = Pattern.compile("(01[016789])[-]?(\\d{3,4})[-]?(\\d{4})");
|
||||
|
||||
// 3. 신한라이프 계좌/증권번호 패턴 (단순 예시용 계좌번호 11~14자리)
|
||||
private static final Pattern ACCOUNT_PATTERN = Pattern.compile("(\\d{3})-?(\\d{3})-?(\\d{5,8})");
|
||||
|
||||
public static String mask(String input) {
|
||||
if (input == null || input.isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
|
||||
String masked = input;
|
||||
|
||||
// [1] 주민번호 뒷자리 마스킹 (첫자리 성별 식별자는 남기고 마스킹: 900101-1******)
|
||||
Matcher rrnMatcher = RRN_PATTERN.matcher(masked);
|
||||
StringBuffer rrnBuffer = new StringBuffer();
|
||||
while (rrnMatcher.find()) {
|
||||
String firstPart = rrnMatcher.group(1);
|
||||
String secondPart = rrnMatcher.group(2);
|
||||
rrnMatcher.appendReplacement(rrnBuffer, firstPart + "-" + secondPart.charAt(0) + "******");
|
||||
}
|
||||
rrnMatcher.appendTail(rrnBuffer);
|
||||
masked = rrnBuffer.toString();
|
||||
|
||||
// [2] 전화번호 중간자리 마스킹 (010-****-5678)
|
||||
Matcher phoneMatcher = PHONE_PATTERN.matcher(masked);
|
||||
StringBuffer phoneBuffer = new StringBuffer();
|
||||
while (phoneMatcher.find()) {
|
||||
String p1 = phoneMatcher.group(1);
|
||||
String p2 = phoneMatcher.group(2);
|
||||
String p3 = phoneMatcher.group(3);
|
||||
String maskedP2 = p2.replaceAll(".", "*");
|
||||
phoneMatcher.appendReplacement(phoneBuffer, p1 + "-" + maskedP2 + "-" + p3);
|
||||
}
|
||||
phoneMatcher.appendTail(phoneBuffer);
|
||||
masked = phoneBuffer.toString();
|
||||
|
||||
// [3] 계좌번호 뒷자리 마스킹 (110-123-********)
|
||||
Matcher accMatcher = ACCOUNT_PATTERN.matcher(masked);
|
||||
StringBuffer accBuffer = new StringBuffer();
|
||||
while (accMatcher.find()) {
|
||||
String a1 = accMatcher.group(1);
|
||||
String a2 = accMatcher.group(2);
|
||||
String a3 = accMatcher.group(3);
|
||||
String maskedA3 = a3.replaceAll(".", "*");
|
||||
accMatcher.appendReplacement(accBuffer, a1 + "-" + a2 + "-" + maskedA3);
|
||||
}
|
||||
accMatcher.appendTail(accBuffer);
|
||||
masked = accBuffer.toString();
|
||||
|
||||
return masked;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.shinhanlife.dap.lib.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Spring AI @Tool 어노테이션을 보완하여 MCP 시스템 메타데이터를 추가 제공하는 힌트 어노테이션
|
||||
* @package io.shinhanlife.dap.lib.annotation
|
||||
* @className GrowToolHint
|
||||
* @description 비즈니스 로직(Tool)과 시스템 제어 메타데이터 분리
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface GrowToolHint {
|
||||
boolean register() default true;
|
||||
boolean requiresApproval() default false;
|
||||
String categoryKey() default "com";
|
||||
String mappingId() default "";
|
||||
String inputSchemaResource() default "";
|
||||
String outputSchemaResource() default "";
|
||||
|
||||
// Meta 정보 추가 (보고용 샘플)
|
||||
String displayDescription() default "";
|
||||
String functionDescription() default "";
|
||||
String whenToUse() default "";
|
||||
String whenNotToUse() default "";
|
||||
String ioLimits() default "";
|
||||
String[] exampleQueries() default {};
|
||||
boolean destructive() default false;
|
||||
boolean idempotent() default false;
|
||||
String[] tags() default {};
|
||||
String[] requiredEnvKeys() default {};
|
||||
String ownerOrg() default "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.shinhanlife.dap.lib.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a response DTO whose generated JSON Schema must be exposed and validated for a Tool response.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface McpOutputSchema {
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package io.shinhanlife.dap.lib.aop;
|
||||
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.aop
|
||||
* @className ToolSlaMonitoringAspect
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
import io.shinhanlife.dap.lib.config.McpProperties;
|
||||
import java.lang.reflect.Method;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ToolSlaMonitoringAspect {
|
||||
|
||||
private final McpProperties mcpProperties;
|
||||
|
||||
// @McpTool 어노테이션이 붙은 모든 비즈니스 툴 메서드 실행을 가로챕니다.
|
||||
@Around("@annotation(org.springaicommunity.mcp.annotation.McpTool)")
|
||||
public Object monitorToolSla(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
McpTool functionAnnotation = method.getAnnotation(McpTool.class);
|
||||
|
||||
// 네임스페이스 자동 주입 로직을 반영하여 최종 툴 이름을 산출합니다.
|
||||
String baseName = functionAnnotation.name();
|
||||
String finalName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
|
||||
? mcpProperties.getNamespace() + "_" + baseName
|
||||
: baseName;
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
|
||||
try {
|
||||
// 실제 비즈니스 로직(툴) 실행
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
stopWatch.stop();
|
||||
long timeMillis = stopWatch.getTotalTimeMillis();
|
||||
|
||||
// SLA 기준을 초과하면 (예: 2초 이상) 경고 로깅 처리 가능
|
||||
if (timeMillis > 2000) {
|
||||
log.warn(" [SLA 경고] Tool: {} | 소요시간: {}ms | 상태: SLOW_RESPONSE", finalName, timeMillis);
|
||||
} else {
|
||||
log.info(" [SLA 추적] Tool: {} | 소요시간: {}ms | 상태: SUCCESS", finalName, timeMillis);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Throwable e) {
|
||||
if (stopWatch.isRunning()) {
|
||||
stopWatch.stop();
|
||||
}
|
||||
long timeMillis = stopWatch.getTotalTimeMillis();
|
||||
|
||||
// 에러 발생 시 명확하게 실패 로그 기록
|
||||
log.error(" [SLA 장애] Tool: {} | 소요시간: {}ms | 상태: FAILED | 사유: {}", finalName, timeMillis, e.getMessage());
|
||||
|
||||
// 원래 흐름대로 예외를 던져서 게이트웨이나 상위 로직이 에러를 처리하게 함
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.shinhanlife.dap.lib.config;
|
||||
|
||||
import io.shinhanlife.glow.communication.module.http.component.GlowHttpComponent;
|
||||
import java.net.http.HttpClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.JdkClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
/**
|
||||
* Registers the temporary Glow HTTP compatibility component from the DAP library scan scope.
|
||||
* The bean is only created when an official GlowHttpComponent has not already been supplied.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class AxhubHttpConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(GlowHttpComponent.class)
|
||||
public GlowHttpComponent glowHttpComponent(RestClient.Builder restClientBuilder) {
|
||||
// WireMock and legacy internal endpoints can only support HTTP/1.1.
|
||||
// Avoid JDK HTTP/2 negotiation that may cause RST_STREAM responses.
|
||||
HttpClient http11Client = HttpClient.newBuilder()
|
||||
.version(HttpClient.Version.HTTP_1_1)
|
||||
.build();
|
||||
JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(http11Client);
|
||||
return new GlowHttpComponent(restClientBuilder.requestFactory(requestFactory));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.shinhanlife.dap.lib.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.config
|
||||
* @className CorsConfig
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**") // 모든 엔드포인트에 대해 CORS 허용
|
||||
.allowedOriginPatterns("*") // 외부 Agent Builder 등 모든 오리진 허용
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH") // 허용할 HTTP 메서드
|
||||
.allowedHeaders("*") // 모든 헤더 허용
|
||||
.exposedHeaders("Mcp-Session-Id") // MCP-HTTP 세션 아이디 노출 허용
|
||||
.allowCredentials(true) // 쿠키/인증 정보 허용
|
||||
.maxAge(3600); // preflight 요청 캐시 시간 (초 단위)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package io.shinhanlife.dap.lib.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* [Glow Framework 통신 환경 설정 클래스]
|
||||
* application-glow-local.yml 의 'glow.communication' 하위 설정값들을
|
||||
* 자바 객체(Bean)로 매핑하여 제공합니다.
|
||||
*/
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.config
|
||||
* @className GlowCommunicationProperties
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Component
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "glow.communication")
|
||||
public class GlowCommunicationProperties {
|
||||
|
||||
private Common common = new Common();
|
||||
private Http http = new Http();
|
||||
private Mci mci = new Mci();
|
||||
private ExtMci extmci = new ExtMci();
|
||||
private Eai eai = new Eai();
|
||||
private Websocket websocket = new Websocket();
|
||||
|
||||
@Getter @Setter
|
||||
public static class Common {
|
||||
private String envType; // 대내표준 헤더의 환경 타입정보 (D, T, P)
|
||||
}
|
||||
|
||||
@Getter @Setter
|
||||
public static class Http {
|
||||
private int connectionTimeout; // 연결 타임아웃 시간 (초 단위)
|
||||
private int readTimeout; // 읽기 타임아웃 시간 (초 단위)
|
||||
}
|
||||
|
||||
@Getter @Setter
|
||||
public static class Mci {
|
||||
private String host;
|
||||
private int port;
|
||||
private String uri;
|
||||
private String receiveUri;
|
||||
private int connectionTimeout;
|
||||
private int readTimeout;
|
||||
private String encoding;
|
||||
}
|
||||
|
||||
@Getter @Setter
|
||||
public static class ExtMci {
|
||||
private String host;
|
||||
private int port;
|
||||
private String uri;
|
||||
private String jsonUri;
|
||||
private String receiveUri;
|
||||
private int connectionTimeout;
|
||||
private int readTimeout;
|
||||
private String encoding;
|
||||
}
|
||||
|
||||
@Getter @Setter
|
||||
public static class Eai {
|
||||
private String host;
|
||||
private int port;
|
||||
}
|
||||
|
||||
@Getter @Setter
|
||||
public static class Websocket {
|
||||
private String endpoint;
|
||||
private String allowedOrigins;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.shinhanlife.dap.lib.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.lib.config
|
||||
* @className McpProperties
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 0986406
|
||||
* @create 2026.09.01
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "mcp")
|
||||
public class McpProperties {
|
||||
|
||||
private String namespace;
|
||||
private Manifest manifest = new Manifest();
|
||||
|
||||
@Data
|
||||
public static class Manifest {
|
||||
private String bundleId;
|
||||
private String namePrefix;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user