133 Commits

Author SHA1 Message Date
jade
8b4d4da0b9 Merge branch 'main' of https://git.devjun.net/kimhyungsik/ax_hub_mcp_tool into DEV-SRTEST 2026-07-29 17:02:21 +09:00
jade
c551b15378 테스트 푸쉬 2026-07-29 17:01:05 +09:00
juheelee
b448e68f45 Merge branch 'main' of https://git.devjun.net/kimhyungsik/ax_hub_mcp_tool
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m49s
2026-07-29 16:50:56 +09:00
juheelee
b68fbb9726 feat: 메타 통합 코드 조회 2026-07-29 16:48:28 +09:00
c6a2f82455 push TEST
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m16s
2026-07-29 16:08:45 +09:00
juheelee
2f5dad05df feat: 메타 통합 코드 조회 2026-07-29 15:34:01 +09:00
jade
b0bf4a9c68 fix: use rsync to clean stale files during host volume sync
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m1s
2026-07-29 13:25:10 +09:00
jade
752aae4dde fix: run gradle natively in runner to avoid isolated mount issue
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1m50s
2026-07-29 13:22:03 +09:00
jade
5cb37cfda6 fix: mount correct app path for gradle build
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 4s
2026-07-29 13:16:31 +09:00
jade
2a4b3e68e9 fix: allow gradle build libs to be copied into docker container
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 2m3s
2026-07-29 13:03:11 +09:00
jade
ca1082f1c2 fix: rollback register to false as per user request
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 31s
2026-07-29 12:58:22 +09:00
jade
7b1d3131e6 fix: set register true for tools to fix catalog display
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 33s
2026-07-29 12:55:06 +09:00
jade
139ddbc6ca fix: optimize dockerfile to use external gradle build
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 37s
2026-07-29 12:54:02 +09:00
jade
870ebb723f fix: hide markdown emphasis markers in chat responses
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m22s
2026-07-29 11:35:22 +09:00
jade
a08a7d25df refactor: move team member tool to smp category
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-29 11:30:52 +09:00
jade
60acc5df81 refactor: rename solgit tool to sol
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m23s
2026-07-29 11:23:49 +09:00
jade
f5be5b2514 refactor: remove unused team member legacy types
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m32s
2026-07-29 11:14:44 +09:00
jade
aae4898d18 feat: invoke Solgit MCI before returning dummy response
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m26s
2026-07-29 11:02:10 +09:00
jade
06b724459e feat: add solgitReqList and get_mcp_tool_team_members tools
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m31s
2026-07-29 10:26:32 +09:00
jade
4133b63595 불필요 한 파일 삭제
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m19s
2026-07-28 14:39:50 +09:00
jade
1e18d2bc47 feat: support nested MCP input schema validation
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-28 14:39:31 +09:00
jade
0c89a09ccf docs: Update README.md with Web UI Scaffolder enhancements
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 8m5s
2026-07-27 15:41:32 +09:00
jade
3ce9201cd5 fix: Add throws Exception to MciClient template 2026-07-27 15:37:27 +09:00
jade
be81c095c9 fix: Correct text block alignment and formatting arguments 2026-07-27 15:36:40 +09:00
jade
d4554ce34f fix: Remove excessive indentation in string formatting for UseCaseImpl text block 2026-07-27 15:30:58 +09:00
jade
b6d4ab1bec fix: Remove duplicated package path in MCI DTOs and Converter 2026-07-27 15:26:38 +09:00
jade
2c8497ebee fix: Correct ToolScaffolder template issues 2026-07-27 15:10:15 +09:00
jade
8a93d5d6dc feat: Support 4-letter MCI system code in Scaffolder and refactor Onnba classes 2026-07-27 15:03:13 +09:00
jade
c0de1f4edb fix: Include local fallback tools in generateToolsMarkdown API
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m15s
2026-07-27 14:11:25 +09:00
jade
1ee9f9e802 style: Add chat.html link to all top navigation bars 2026-07-27 14:07:33 +09:00
jade
25f0d2bab5 feat: move Onnba MCI request conversion to use case
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m1s
2026-07-27 14:01:04 +09:00
jade
9b9159a605 feat: Add UI/UX improvements to catalog.html including search, config json copy, and guide modal
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 34s
2026-07-27 14:00:27 +09:00
jade
c8dd43221e ci: Fix Node.js installation by dropping sudo/curl and supporting alpine
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 6m41s
2026-07-27 13:09:01 +09:00
jade
7b8c38489e ci: Add Node.js installation step to Gitea Actions deploy workflow
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1s
2026-07-27 13:07:29 +09:00
jade
63187429b4 feat: validate MCP tool input constraints
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1s
2026-07-27 13:01:40 +09:00
jade
d4953d60ec test: fix gateway test package references
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 18s
2026-07-27 12:51:28 +09:00
jade
72891dc2db 불필요한 소스 삭제
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 12:38:31 +09:00
jade
82c27bd468 test: prevent duplicate MCP tool names
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 12:37:35 +09:00
jade
ff5ca4fc7a Fix: Add missing formatted arguments for MCI and EAI ToolScaffolder templates 2026-07-27 11:43:37 +09:00
jade
ba39a23b09 Fix: Add missing @Service annotations to MCP Tool use case implementations
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 10:45:09 +09:00
jade
579979b5fe Refactor: Move MCP tool annotations to interface level 2026-07-27 10:21:24 +09:00
jade
db46f30e72 refactor: DTO 레코드를 별도 파일(dto 패키지)로 분리
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 10:06:43 +09:00
jade
2c64d86a56 refactor: UseCase 인터페이스 내 DTO 분리 및 강결합 제거
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 10:04:56 +09:00
jade
ded5ef9e8f 신한 라이프 경로에 맞게 수정
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-27 08:57:03 +09:00
jade
a6ca2b82a7 scaffold 수정
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-26 16:00:45 +09:00
jade
94cdaaa8c9 불필요 없는 소스 삭제
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-26 15:46:48 +09:00
jade
bea517c4c1 fix: resolve bean injection error and gateway routing configs
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-26 15:34:43 +09:00
jade
ad950071b2 refactor: fix annotation package - remove duplicate annotation.annotation directory
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 02:00:47 +09:00
jade
e6407b07a2 refactor: apply Glow standard to dap-tool-core (usecase, javadoc, etc)
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 01:56:41 +09:00
jade
e58c004d9d refactor: rename biz/other to biz/oth
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 01:43:47 +09:00
jade
92fe2399be refactor: rename dap-tool-other to dap-tool-oth
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 01:36:12 +09:00
jade
7ba18f7809 refactor: rename domain categories (common->cmm, sample->smp) and restrict category key to 3 chars
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 01:29:48 +09:00
jade
4dcc5a2978 refactor: restructure MCP tools without Controller layer, using UseCase pattern per Glow standards
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 01:13:25 +09:00
jade
994f5b4348 fix: remove docker compose down from deploy pipeline to prevent killing the CI runner
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 00:13:57 +09:00
jade
0a50b20960 feat: add chat.html link to index.html dashboard
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 00:13:00 +09:00
jade
97ba0c3267 fix: add --remove-orphans to docker compose down to prevent port conflicts with legacy Blue/Green containers
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-25 00:09:36 +09:00
jade
388fa33c67 fix: revert Nginx and Blue/Green deployment to restore stable Apache connection
Some checks are pending
Deploy to OCIWP / deploy (push) Waiting to run
2026-07-25 00:05:54 +09:00
jade
4015207b86 fix: map Nginx 8281 to host 8080 to restore Apache proxy connection
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 7m53s
2026-07-24 23:52:55 +09:00
jade
4dcc85eff0 fix: override gateway fallback URLs via env vars to support blue/green
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 23:42:30 +09:00
jade
72f04aef62 fix: remove curl command that fails in act_runner
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 11m35s
2026-07-24 23:26:48 +09:00
jade
b5565a4da0 fix: repair blue-green deployment architecture
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 54s
2026-07-24 23:24:55 +09:00
jade
c38d59887c fix: remove 8080 from deploy script
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 10m59s
2026-07-24 23:04:38 +09:00
jade
f3639043fc chore: fetch gateway logs in deploy action 2026-07-24 17:52:15 +09:00
jade
e278602d32 fix: map gateway to 8281 to match Apache 2026-07-24 17:51:38 +09:00
jade
f6f86e5afb chore: test curl to gateway inside deploy action 2026-07-24 17:51:03 +09:00
jade
a89843518b fix: restore gateway 8081 port mapping 2026-07-24 17:48:34 +09:00
jade
d7b80a644c fix: bypass nginx and map gateway directly to 8281 2026-07-24 17:47:41 +09:00
jade
05a242e5de chore: test nginx static HTML response 2026-07-24 17:46:46 +09:00
jade
a409652bdf fix: Nginx port 8281 mapping restored 2026-07-24 17:46:09 +09:00
jade
fa268edf7d fix: Nginx SSL support for Apache proxy 2026-07-24 17:44:23 +09:00
jade
c69f11e1c9 fix: add http2 support to Nginx to match Apache h2c proxying
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m41s
2026-07-24 17:42:25 +09:00
jade
56483d804a chore: test nginx proxy to google
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 17:41:33 +09:00
jade
1c353ce3a7 chore: test nginx plain response
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 17:39:36 +09:00
jade
35f361a976 fix: restore Nginx port 8281 mapping - Apache VirtualHost proxies to 8281
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m41s
2026-07-24 16:08:59 +09:00
jade
9066c621a0 fix: resolve Nginx 503 error on rollback and apply package refactoring
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 11m44s
2026-07-24 15:00:01 +09:00
jade
4ed534b1d6 fix: restore Nginx 8080 port mapping for Apache and refactor MciCfpaClient
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m42s
2026-07-24 14:27:00 +09:00
jade
0892597c31 fix: start containers sequentially and fix nginx startup config
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 3m20s
2026-07-24 13:29:43 +09:00
jade
6416d3f844 fix: revert Nginx port mapping to 8281 to match external Apache proxy
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 13:21:10 +09:00
jade
dbe479a64b fix: build sequentially to avoid OOM on dev server
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m8s
2026-07-24 13:04:42 +09:00
jade
53f5047c8e fix: map Nginx 8281 to host 8080 to restore Apache proxy connection
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 12m3s
2026-07-24 11:44:01 +09:00
jade
f56e503a29 fix: make Blue-Green deployment safe by checking Nginx reload status and removing redundant host Gradle build to prevent OOM server crashes
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 10m6s
2026-07-24 10:55:32 +09:00
jade
aae95591a0 fix: add Nginx SSE proxy configs to prevent buffering of AI streams, and fix Gateway internal routing to use Nginx
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 10:45:27 +09:00
jade
227edf9744 fix: remove stale src directories in host volume before copy to resolve compilation conflict
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 12m14s
2026-07-24 10:28:24 +09:00
jade
12ac05c805 fix: add clean to gradle build in Gitea deploy pipeline to clear persistent host volume cache
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 38s
2026-07-24 10:26:09 +09:00
jade
74ea89bf1c refactor: apply naming convention for MCI interface IO objects (CLCNNB00001_I, CUST_INQ_001_I) and separate layers
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 24s
2026-07-24 10:24:00 +09:00
jade
d562e35ad8 fix: resolve stale class conflict in Docker build by adding clean and .dockerignore
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 23s
2026-07-24 10:20:00 +09:00
jade
fc8c3da666 refactor: apply MSA naming standard for DTOs and Scaffold template (Req->Request, Res->Response)
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 30s
2026-07-24 10:07:50 +09:00
jade
438c190447 refactor: rename packages dapms to mcg and dapmt to mcc
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 42s
2026-07-24 10:00:45 +09:00
jade
51f37cfcbc chore: add restart always policy to nginx
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 14m33s
2026-07-24 09:45:23 +09:00
jade
44c2fcebba fix: invalid docker filter syntax in deploy.yml
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m9s
2026-07-24 09:15:02 +09:00
jade
2758f6da8e fix: Nginx port conflict with legacy containers
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 14m45s
2026-07-24 08:55:30 +09:00
jade
8b11c1aae8 feat: 적용 무중단 배포 시스템 (Blue-Green Deployment)
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 51s
2026-07-24 08:51:01 +09:00
jade
60a7226199 chore: remove unnecessary Node.js installation from deploy.yml
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m32s
2026-07-24 00:29:02 +09:00
jade
b3bdaa2b28 fix: revert ports and add zombie container cleanup to CI
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-24 00:22:20 +09:00
jade
260f59b143 fix: change dozzle port to 18288 to resolve conflict
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 13m26s
2026-07-24 00:02:54 +09:00
jade
ad2ab985d8 feat: allow Chat AI to use unregistered (register=false) tools
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 13m58s
2026-07-23 23:46:04 +09:00
jade
18959b5128 fix: install nodejs for checkout action
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-23 23:32:44 +09:00
jade
7f85b10938 chore: remove accidentally committed SearchHr generated files
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1s
2026-07-23 23:30:53 +09:00
jade
b5dbcc54f0 fix: add checkout step and sync code to host volume in deployment pipeline
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 8s
2026-07-23 23:28:29 +09:00
jade
abf7a435a4 feat/fix: update ToolScaffolder interface, update scaffold.html, fix mci-mock port
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 14m20s
2026-07-23 23:11:30 +09:00
jade
f0a295632f ci: add docker system prune before deployment
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 16m15s
2026-07-23 22:52:48 +09:00
jade
cec56e015b fix: change Redis host port mapping to avoid conflicts
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 11m48s
2026-07-23 22:33:09 +09:00
kimhyungsik
1e54370fb8 fix: restore missing closing brace in DynamicMcpController
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 15m36s
2026-07-23 13:08:16 +09:00
kimhyungsik
408a3f6b28 fix: add DELETE mapping and .well-known endpoints for Cursor compatibility
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1m23s
2026-07-23 13:05:20 +09:00
jade
541150d3f4 Fix: gateway local profile fallback URL을 컨테이너 이름으로 변경
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-23 13:01:53 +09:00
jade
165a6340ea Refactor: ToolService 인터페이스 분리 및 GlowEaiComponent 로드 에러 수정
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-23 12:59:34 +09:00
kimhyungsik
5f8228bfce fix: add EnableScheduling to enable dynamic tool synchronization
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 17m7s
2026-07-23 11:16:54 +09:00
kimhyungsik
6893bb6b35 fix: comment out emitter.onCompletion/onTimeout session removal to keep sessions persistent
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 14m21s
2026-07-23 10:33:56 +09:00
jade
3c183e901b chore: Remove hardcoded axhub.tool.url from application-dev.yml
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m57s
2026-07-23 10:17:38 +09:00
kimhyungsik
2948465b8a fix: comment out emitter.complete() to allow keep-alive sessions for standard SSE MCP client
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-23 10:16:15 +09:00
jade
2b4adb45d2 fix: Correct tool-payment internal port mapping to 8085
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-23 10:10:45 +09:00
jade
323d227eee feat: Add AxhubEaiComponent and MCI/EAI mock frameworks
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 3m26s
2026-07-23 09:19:21 +09:00
kimhyungsik
74b50482bf chore: optimize dev fallback routes to use internal docker service names
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 13m24s
2026-07-22 17:29:00 +09:00
kimhyungsik
dfa5a73b20 chore: force docker compose project name to ax_hub_mcp_tool
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 7m48s
2026-07-22 16:44:29 +09:00
kimhyungsik
86302d0947 chore: optimize deploy pipeline to ultra-fast relay
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-22 16:31:13 +09:00
kimhyungsik
ad37714c5b chore_fix_docker_compose_typo
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 13m31s
2026-07-22 16:01:03 +09:00
jade
b57d96f83f refactor: rename project codes mcg to dapms and mcc to dapmt
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 37s
2026-07-22 15:48:45 +09:00
kimhyungsik
fabbd368a2 chore_resolve_path_and_arg_issues
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 57s
2026-07-22 15:37:33 +09:00
kimhyungsik
f3cdfaccc3 chore_apply_gradle_jdk21_build_and_compose_direct_mount
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 34s
2026-07-22 15:33:57 +09:00
kimhyungsik
e42ca92811 chore_resolve_git_conflict
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 15s
2026-07-22 15:31:13 +09:00
jade
c18efe251e refactor: migrate all properties files to yaml
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 14:57:44 +09:00
jade
8d4e8fd976 chore: replace author name with employee ID 0986406
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 1s
2026-07-22 14:36:15 +09:00
kimhyungsik
edec314a83 test: final verify auto deploy
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 14:08:45 +09:00
kimhyungsik
da09997452 chore: enable docker run relay deploy
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 14:05:46 +09:00
kimhyungsik
5c15ae3505 test: verify auto deploy triggering
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 14:03:22 +09:00
kimhyungsik
3eebf07b0e chore: restore standard runs-on label
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 14:00:36 +09:00
kimhyungsik
a161dcf319 chore: quote runs-on host label
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-22 13:59:46 +09:00
kimhyungsik
ae3352ccb4 chore: fix runs-on syntax and add gradle caching
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 13:57:00 +09:00
kimhyungsik
2deffd3f10 chore: change runs-on to host mode
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
2026-07-22 13:52:22 +09:00
kimhyungsik
f334b8ecc5 feat: add deploy workflow
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 0s
2026-07-22 13:47:01 +09:00
jade
1db19344bc fix: restore broken Korean comments in application-dev.properties and add UTF-8 encoding rule 2026-07-22 13:36:22 +09:00
jade
8e6682d089 chore: migrate environment endpoints from render to OCI 2026-07-22 13:35:01 +09:00
jade
6968c7dfb7 refactor: use Spring DI for MapStruct and update AGENTS.md rule 2026-07-22 12:37:16 +09:00
339 changed files with 4928 additions and 3952 deletions

View File

@@ -5,9 +5,10 @@
## 개발 가이드라인 ## 개발 가이드라인
* 패키지명은 `controller` 대신 `presentation`을 사용합니다. * 패키지명은 `controller` 대신 `presentation`을 사용합니다.
* MapStruct 사용 시, 테스트 환경 에러를 방지하기 위해 생성자(`new ...Impl()`) 대신 `Mappers.getMapper(인터페이스명.class)` 방식으로 인스턴스를 가져옵니다. * MapStruct 사용 시, Spring DI를 활용하여 의존성 주입(`private final Converter converter;`)을 받는 방식을 권장합니다. (단위 테스트 시에는 `@MockBean` 또는 직접 구현체를 주입하여 테스트)
## 명심해야 할 규칙 추가란 ## 명심해야 할 규칙 추가란
* `application.yml` 등 설정 파일 수정 시 한글이 깨지지 않도록 항상 UTF-8 인코딩을 유지하고, 깨진 문자열(`?\uFFFD` 등)이 발생하지 않도록 각별히 주의한다.
* 이모지는 무조건 넣지 않는다 * 이모지는 무조건 넣지 않는다
* import 할것 무조건 한다 * import 할것 무조건 한다
* Git commit과 push는 사용자의 명시적인 허락(지시) 없이는 절대 수행하지 않는다. * Git commit과 push는 사용자의 명시적인 허락(지시) 없이는 절대 수행하지 않는다.
@@ -16,13 +17,13 @@
* @package io.shinhanlife.axhub.biz.mcp.tool.sms * @package io.shinhanlife.axhub.biz.mcp.tool.sms
* @className AxHubToolSmsApplication * @className AxHubToolSmsApplication
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

10
.dockerignore Normal file
View File

@@ -0,0 +1,10 @@
.git
.gradle
.idea
/build/
target/
*/target/
bin/
*/bin/
out/
*/out/

View File

@@ -0,0 +1,67 @@
name: Deploy to OCIWP
on:
push:
branches:
- main
- master
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Prepare Environment (Install Node.js & Git & Java 21)
run: |
if command -v apt-get &> /dev/null; then
apt-get update
apt-get install -y nodejs git openjdk-21-jdk rsync
elif command -v apk &> /dev/null; then
apk add --no-cache nodejs git openjdk21 rsync
fi
- name: Checkout Code
uses: actions/checkout@v3
- name: Sync Code to Host Volume
run: |
echo "Copying latest code to /app (Host Volume) and removing stale files..."
if command -v rsync &> /dev/null; then
rsync -a --delete --exclude='.git' . /app/
else
rm -rf /app/dap-* /app/src /app/build.gradle /app/settings.gradle
cp -a . /app/
fi
- name: Deploy Task on Host
run: |
echo "Starting Standard CI/CD Deploy pipeline..."
# 1. runner에 설치된 java로 직접 빌드! (격리된 환경 문제 해결)
cd /app
chmod +x gradlew
./gradlew bootJar -x test
# 2. 빌드 결과 plain jar 아카이브 정리
find /app -name "*-plain.jar" -delete
# 3. 좀비 컨테이너 청소 (현재 우리가 쓸 포트를 점유 중인 옛날 컨테이너들만 정확히 색출해서 사살)
echo "Finding and killing zombie containers holding our ports..."
for port in 6379 8080 8089 8281 8282 8283 8284 8285 8288; do
cid=$(docker ps -q --filter "publish=$port")
if [ ! -z "$cid" ]; then
echo "Force killing container $cid using port $port"
docker rm -f $cid
fi
done
# 4. 마운트된 /app 디렉토리로 이동하여 호스트의 도커 컴포즈 제어!
cd /app
docker system prune -f
ACTIVE_PROFILE=dev docker compose up -d --build --remove-orphans gateway redis mci-mock dozzle tool-sms tool-oth
# 5. 배포 후 대롱대롱 매달려 있는 가비지 이미지 자동 소거 청소!
docker image prune -f
echo "CI/CD Deploy Success!"

62
.gitignore vendored
View File

@@ -56,11 +56,69 @@ build/
# ===== VS Code ===== # ===== VS Code =====
.vscode/ .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 ===== # ===== OS =====
.DS_Store .DS_Store
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db
# ===== ?섍꼍?ㅼ젙 (誘쇨컧?뺣낫 遺꾨━ ?? ===== # ===== ?섍꼍?ㅼ젙 (誘쇨컧?뺣낫 遺꾨━ ?? =====
# application-local.properties # application-local.yml
# application-secret.properties # application-secret.yml

View File

@@ -1,30 +1,31 @@
# 1. ??š®ë±???<3F>ê¼<EFBFBD> (JDK 21) # 1. ??<EFBFBD><EFBFBD><EFBFBD>???<3F> (JDK 21)
FROM eclipse-temurin:21-jdk-alpine AS builder FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app WORKDIR /app
# Gradle ??ë<EFBFBD><EFBFBD>?? ???’ª 蹂듭ê¶? # Gradle ??<3F>?? ???<EFBFBD><EFBFBD> 蹂듭<E8B982>?
COPY gradlew . COPY gradlew .
COPY gradle gradle COPY gradle gradle
COPY build.gradle settings.gradle ./ COPY build.gradle settings.gradle ./
COPY src src COPY src src
# æ²…ëš°ë¸??ºÂ€??è«???š®ë±?(???’ª????–쇅) # 沅뚰<EFBFBD>??<3F>€??<3F>???<3F><><EFBFBD>?(???<EFBFBD><EFBFBD>????<EFBFBD>)
RUN chmod +x gradlew RUN chmod +x gradlew
RUN ./gradlew clean build -x test RUN ./gradlew clean build -x test
# 2. ??½ë»¾ ??<3F>ê¼<EFBFBD> (JRE 21) # 2. ??<EFBFBD> ??<3F> (JRE 21)
FROM eclipse-temurin:21-jre-alpine FROM eclipse-temurin:21-jre-alpine
WORKDIR /app WORKDIR /app
# ???꾩ã€???¼ì ™ (??“뎅 ??“ì»™) # ???<EFBFBD>???<3F>젙 (??<3F>뎅 ??<3F>)
RUN apk add --no-cache tzdata RUN apk add --no-cache tzdata
ENV TZ=Asia/Seoul ENV TZ=Asia/Seoul
# ??š®ë±??JAR ???”ª 蹂듭ê¶? # ??<EFBFBD><EFBFBD><EFBFBD>??JAR ???<EFBFBD><EFBFBD> 蹂듭<E8B982>?
COPY --from=builder /app/build/libs/*.jar app.jar COPY --from=builder /app/build/libs/*.jar app.jar
# 湲곕???????몄텧 # 湲곕???????몄텧
EXPOSE 8081 EXPOSE 8081
# ?Œâ‘¦???€ê¼???½ë»¾ ??JAR ??½ë»¾ # ?<EFBFBD>⑦???<3F><>???<3F> ??JAR ??<EFBFBD>
ENTRYPOINT ["java", "-jar", "app.jar"] ENTRYPOINT ["java", "-jar", "app.jar"]

View File

@@ -2,13 +2,13 @@
* @package io.shinhanlife * @package io.shinhanlife
* @className McpBridge * @className McpBridge
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

319
README.md
View File

@@ -1,165 +1,154 @@
# DAP Backend # DAP Backend
Spring Boot 기반 DAP 관리자 백엔드 API 서버 및 MCP(Model Context Protocol) Gateway / Tool 분산 서버 프로젝트입니다. Spring Boot 기반 DAP 관리자 백엔드 API 서버 및 MCP(Model Context Protocol) Gateway / Tool 분산 서버 프로젝트 입니다.
--- ---
## 아키텍처 개요 (Architecture Overview) ## 아키텍처 개요 (Architecture Overview)
DAP Backend는 2개의 주요 애플리케이션으로 분리 운영됩니다: DAP Backend는 2개의 주요 애플리케이션으로 분리 운영됩니다:
1. **MCP Gateway (`DapGatewayApplication`)**: 외부 LLM(Claude, GPT 등) 서버의 MCP 통신을 받아, 내부 Tool 서버들로 분배(라우팅)하는 허브 서버이자 관리자 웹(Scaffolder)을 제공하는 통합 서버 (포트: 8081) 1. **MCP Gateway (`DapGatewayApplication`)**: 외부 LLM(Claude, GPT 등) 서버의 MCP 통신을 받아, 내부 Tool 서버들로 분배(라우팅)하는 허브 서버이자 관리자 웹(Scaffolder)을 제공하는 통합 서버 (포트: 8081)
2. **MCP Tool (`DapTool*Application`)**: 실제 레거시 시스템(MCI, EAI 등)과 통신하여 비즈니스 로직(결제, 휴가신청 등)을 수행하는 어댑터 서버 (포트: 8082~8085 등 분산 구성 가능) 2. **MCP Tool (`DapTool*Application`)**: 실제 레거시 시스템(MCI, EAI 등)과 통신하여 비즈니스 로직(결제, 휴가신청 등)을 수행하는 어댑터 서버 (포트: 8082~8085 등 분산 구성 가능)
--- ---
## 환경 (Environment) ## 환경 (Environment)
| 항목 | 버전 | | 항목 | 버전 |
|------|------| |------|------|
| Java | 21 | | Java | 21 |
| Spring Boot | 4.0.5 | | Spring Boot | 4.0.5 |
| Build Tool | Gradle | | Build Tool | Gradle |
| 주요 기술 스택 | MyBatis, Lombok, MapStruct, P6Spy | | 주요 기술 스택 | MyBatis, Lombok, MapStruct, P6Spy |
| 데이터베이스 | H2 (in-memory, 로컬 개발용) | | 데이터베이스 | H2 (in-memory, 로컬 개발용) |
| 세션/캐시 저장소 | Redis | | 세션/캐시 저장소 | Redis |
| **장애 격리 / 제어** | **Resilience4j (RateLimiter, CircuitBreaker, Retry)** | | **장애 격리 / 제어** | **Resilience4j (RateLimiter, CircuitBreaker, Retry)** |
| **메시지 큐** | **Kafka (트래픽 폭주 시 대기열 전환용)** | | **메시지 큐** | **Kafka (트래픽 폭주 시 대기열 전환용)** |
--- ---
## ▶ 실행 방법 (How to Run) ## ▶ 실행 방법 (How to Run)
### 1. Gateway & Tool 서버 실행 (MCP 연동용) ### 1. Gateway & Tool 서버 실행 (MCP 연동용)
- **Gateway 서버 기동:** - **Gateway 서버 기동:**
- `./gradlew :dap-gateway:bootRun` - `./gradlew :dap-gateway:bootRun`
- **Tool 서버 기동:** - **Tool 서버 기동:**
- `./gradlew :dap-tool-other:bootRun` (또는 dap-tool-payment 등) - `./gradlew :dap-tool-oth:bootRun` (또는 dap-tool-payment 등)
- Tool 서버가 기동되면 자동으로 Gateway(8081)에 자신을 등록(Auto-Registration)합니다. - Tool 서버가 기동되면 자동으로 Gateway(8081)에 자신을 등록(Auto-Registration)합니다.
- **(선택) 특정 Tool 그룹만 실행하기:** - **(선택) 특정 Tool 그룹만 실행하기:**
- 업무 특성에 따라 세분화된 그룹에 속한 Tool만 띄우고 싶다면, 실행 인수에 `--mcp.tool.target=그룹명`을 추가합니다. - 업무 특성에 따라 세분화된 그룹에 속한 Tool만 띄우고 싶다면, 실행 인수에 `--mcp.tool.target=그룹명`을 추가합니다.
- **지원되는 그룹명:** - **지원되는 그룹명:**
- `NOTIFICATION`: 이메일, SMS 발송 - `NOTIFICATION`: 이메일, SMS 발송
- `CLAIM`: 청구 처리, 심사 상태 조회 - `CLAIM`: 청구 처리, 심사 상태 조회
- `POLICY`: 증권 발행, 발행 가능 여부 조회 - `POLICY`: 증권 발행, 발행 가능 여부 조회
- `HR`: 휴가 등록, 연차 갯수 조회 - `HR`: 휴가 등록, 연차 갯수 조회
- `CONTRACT`: 계약 상태, 계약 상세 조회 - `CONTRACT`: 계약 상태, 계약 상세 조회
- `CUSTOMER`: 고객 등급, 고객 상세 정보 조회 - `CUSTOMER`: 고객 등급, 고객 상세 정보 조회
- `SAMPLE`: 날씨, 환율, 명언 조회 등 외부 연동 샘플 - `SAMPLE`: 날씨, 환율, 명언 조회 등 외부 연동 샘플
- IntelliJ IDEA: `Run/Debug Configurations`에서 `DapTool*Application``Program arguments``--mcp.tool.target=NOTIFICATION` 입력 - IntelliJ IDEA: `Run/Debug Configurations`에서 `DapTool*Application``Program arguments``--mcp.tool.target=NOTIFICATION` 입력
--- ---
## 🤖 AI Agent 연동 아키텍처 (MCP & Agent Builder) ## 🤖 AI Agent 연동 아키텍처 (MCP & Agent Builder)
본 시스템은 **투트랙(Two-Track) AI 연동 아키텍처**를 제공하여 로컬 개발 환경과 프로덕션 환경 모두를 완벽하게 지원합니다. 본 시스템은 **투트랙(Two-Track) AI 연동 아키텍처**를 제공하여 로컬 개발 환경과 프로덕션 환경 모두를 완벽하게 지원합니다.
### 1. 로컬 코딩 AI (Antigravity, Cursor, Claude Desktop 등) 연동 ### 1. 로컬 코딩 AI (Antigravity, Cursor, Claude Desktop 등) 연동
표준 MCP 통신(Stdio)을 요구하는 로컬 AI 에이전트를 위해 자바 기반의 브릿지 스크립트(`McpBridge.java`)를 내장하고 있습니다. 브릿지가 Stdio 요청을 HTTP로 변환하여 로컬 환경의 Gateway(포트: 8281)로 전달합니다. 표준 MCP 통신(Stdio)을 요구하는 로컬 AI 에이전트를 위해 자바 기반의 브릿지 스크립트(`McpBridge.java`)를 내장하고 있습니다. 브릿지가 Stdio 요청을 HTTP로 변환하여 로컬 환경의 Gateway(포트: 8281)로 전달합니다.
- **설정 방법**: IDE의 `mcp_config.json` 설정 파일에 아래와 같이 등록합니다. - **설정 방법**: IDE의 `mcp_config.json` 설정 파일에 아래와 같이 등록합니다.
```json ```json
"mcpServers": { "mcpServers": {
"dap-gateway": { "dap-gateway": {
"command": "java", "command": "java",
"args": ["C:/절대경로/dap-backend-main/McpBridge.java"] "args": ["C:/절대경로/dap-backend-main/McpBridge.java"]
} }
} }
``` ```
- **특정 카테고리 툴 필터링**: `McpBridge.java` 내부의 URI 파라미터(`?categoryKey=sample` 등)를 수정하여 원하는 도메인의 툴만 선택적으로 AI에게 학습시킬 수 있습니다. - **특정 카테고리 툴 필터링**: `McpBridge.java` 내부의 URI 파라미터(`?categoryKey=sample` 등)를 수정하여 원하는 도메인의 툴만 선택적으로 AI에게 학습시킬 수 있습니다.
### 2. 프로덕션 클라우드 AI (Google Cloud Agent Builder 등) 연동 ### 2. 프로덕션 클라우드 AI (Google Cloud Agent Builder 등) 연동
실제 라이브 서비스에서 동작하는 클라우드 Agent Builder는 REST API 기반의 OpenAPI Spec을 요구합니다. 실제 라이브 서비스에서 동작하는 클라우드 Agent Builder는 REST API 기반의 OpenAPI Spec을 요구합니다.
`dap-gateway`는 이미 **Agent Builder 규격의 REST API(`/mcp/api/v1/tools/call`)를 네이티브로 제공**하므로, 별도의 브릿지나 어댑터 없이 Endpoint URL과 Swagger(OpenAPI) 문서만 클라우드 콘솔에 등록하면 즉시 라이브 챗봇/에이전트로 서비스할 수 있습니다. `dap-gateway`는 이미 **Agent Builder 규격의 REST API(`/mcp/api/v1/tools/call`)를 네이티브로 제공**하므로, 별도의 브릿지나 어댑터 없이 Endpoint URL과 Swagger(OpenAPI) 문서만 클라우드 콘솔에 등록하면 즉시 라이브 챗봇/에이전트로 서비스할 수 있습니다.
--- ---
## 비공개 Tool 관리 및 Fallback 연동 (Visibility & Routing) ## 비공개 Tool 관리 및 Fallback 연동 (Visibility & Routing)
저희 시스템은 MSA 보안 및 아키텍처 원칙에 따라 Tool의 **레지스트리 등록 여부(라우팅)**와 **API 노출 여부(가시성)**를 완벽히 분리하여 관리합니다. 저희 시스템은 MSA 보안 및 아키텍처 원칙에 따라 Tool의 **레지스트리 등록 여부(라우팅)**와 **API 노출 여부(가시성)**를 완벽히 분리하여 관리합니다.
1. **`visible = false`**: 1. **`visible = false`**:
레지스트리에 정상적으로 등록되어 게이트웨이가 동적으로 라우팅하지만, 클라이언트에게 제공되는 `/tools/list` API 목록에서는 숨겨집니다. 레지스트리에 정상적으로 등록되어 게이트웨이가 동적으로 라우팅하지만, 클라이언트에게 제공되는 `/tools/list` API 목록에서는 숨겨집니다.
2. **`register = false`**: 2. **`register = false`**:
내부 레지스트리(Redis)에 툴 정보를 등록하지 않습니다 (외부 레지스트리를 독자적으로 사용할 경우 등). 내부 레지스트리(Redis)에 툴 정보를 등록하지 않습니다 (외부 레지스트리를 독자적으로 사용할 경우 등).
이 경우 게이트웨이는 `application.properties`의 `mcp.gateway.fallback.routes` 설정을 참조하여 **Fallback 정적 라우팅**을 수행하므로 연동이 100% 보장됩니다. 이 경우 게이트웨이는 `application.yml`의 `mcp.gateway.fallback.routes` 설정을 참조하여 **Fallback 정적 라우팅**을 수행하므로 연동이 100% 보장됩니다.
```java ```java
@McpFunction( @McpFunction(
name = "secret_tool", name = "secret_tool",
visible = false, // 목록 숨김 여부 (기본값: true) visible = false, // 목록 숨김 여부 (기본값: true)
register = false // 내부 Redis 등록 여부 (기본값: true) register = false // 내부 Redis 등록 여부 (기본값: true)
) )
``` ```
--- ---
## 🛡️ 시스템 안정성 및 네트워크 제어 (Resilience & Network) ## 🛡️ 시스템 안정성 및 네트워크 제어 (Resilience & Network)
MSA 및 외부 시스템(MCI) 연동 환경의 안정성을 위해 완벽한 3-Tier 방어 체계를 구축했습니다. MSA 및 외부 시스템(MCI) 연동 환경의 안정성을 위해 완벽한 3-Tier 방어 체계를 구축했습니다.
1. **Gateway 라우팅 방어 (Timeout & Fallback):** 1. **Gateway 라우팅 방어 (Timeout & Fallback):**
- MCP 라우터(`McpRouterController`) 단에 1초 타임아웃을 강제 적용하여 특정 Tool Pod의 응답 지연이 전체 시스템 장애로 이어지는 것을 방지하고 신속하게 정적 Fallback 라우팅으로 전환합니다. - MCP 라우터(`McpRouterController`) 단에 1초 타임아웃을 강제 적용하여 특정 Tool Pod의 응답 지연이 전체 시스템 장애로 이어지는 것을 방지하고 신속하게 정적 Fallback 라우팅으로 전환합니다.
2. **MCI 네트워크 안정화 (HTTP/1.1 Downgrade):** 2. **MCI 네트워크 안정화 (HTTP/1.1 Downgrade):**
- 기존 HTTP/2 사용 시 레거시 시스템 연동 중 간헐적으로 발생하던 `RST_STREAM` 오류를 원천 차단하기 위해, MCI 전용 `HttpEimsSender`에는 고도로 최적화된 **HTTP/1.1 전용 커넥션 풀(Factory)**이 고정 적용되어 네트워크 단절을 방지합니다. - 기존 HTTP/2 사용 시 레거시 시스템 연동 중 간헐적으로 발생하던 `RST_STREAM` 오류를 원천 차단하기 위해, MCI 전용 `HttpEimsSender`에는 고도로 최적화된 **HTTP/1.1 전용 커넥션 풀(Factory)**이 고정 적용되어 네트워크 단절을 방지합니다.
3. **Resilience4j 기반 트래픽 제어:** 3. **Resilience4j 기반 트래픽 제어:**
- **Gateway 계층 (동적 방어):** Tool 등록 시 제출된 SLA 메타데이터를 기반으로 동적 CircuitBreaker 및 RateLimiter를 가동하며, 한계치 초과 시 Kafka 큐로 비동기 전환합니다. - **Gateway 계층 (동적 방어):** Tool 등록 시 제출된 SLA 메타데이터를 기반으로 동적 CircuitBreaker 및 RateLimiter를 가동하며, 한계치 초과 시 Kafka 큐로 비동기 전환합니다.
- **Tool 계층 (정적 방어):** 레거시 커넥터 내부에 `@CircuitBreaker`, `@RateLimiter` 어노테이션 기반의 장애 전파 차단 로직이 2차적으로 가동됩니다. - **Tool 계층 (정적 방어):** 레거시 커넥터 내부에 `@CircuitBreaker`, `@RateLimiter` 어노테이션 기반의 장애 전파 차단 로직이 2차적으로 가동됩니다.
--- ---
## 모듈(Pod) 및 Tool 코드 자동 생성 (Scaffolders) ## 모듈(Pod) 및 Tool 코드 자동 생성 (Scaffolders)
새로운 도메인의 기능을 추가할 때 발생하는 반복적인 설정(보일러플레이트, 설정 파일 복사 등)을 1초 만에 자동화하기 위해 **DAP Developer Portal (Web UI)** 및 **CLI 스캐폴더 2종**을 제공합니다. 새로운 도메인의 기능을 추가할 때 발생하는 반복적인 설정(보일러플레이트, 설정 파일 복사 등)을 1초 만에 자동화하기 위해 **DAP Developer Portal (Web UI)** 및 **CLI 스캐폴더 2종**을 제공합니다.
### 1. DAP Developer Portal (Web UI) - 가장 추천하는 방식! ### 1. DAP Developer Portal (Web UI) - 가장 추천하는 방식!
이제 더 이상 터미널에서 명령어를 칠 필요가 없습니다. Gateway 모듈에 내장된 웹 화면에서 빈칸만 채우면 코드가 마법처럼 찍혀 나옵니다. 이제 더 이상 터미널에서 명령어를 칠 필요가 없습니다. Gateway 모듈에 내장된 웹 화면에서 빈칸만 채우면 신한라이프 패키지 개발 가이드에 맞춘 코드가 마법처럼 찍혀 나옵니다.
1. **접속 방법**: Gateway 서버 기동 후 브라우저에서 `http://localhost:8081/admin/scaffold.html` 접속 1. **접속 방법**: Gateway 서버 기동 후 브라우저에서 `http://localhost:8081/admin/scaffold.html` 접속
2. **Pod (모듈) 생성 탭**: 모듈명(예: hr)과 포트만 입력하면 독립적인 Spring Boot 모듈이 디렉토리부터 빌드 스크립트까지 완벽히 생성됩니다. 2. **Pod (모듈) 생성 탭**: 모듈명(예: hr)과 포트만 입력하면 독립적인 Spring Boot 모듈이 디렉토리부터 빌드 스크립트까지 완벽히 생성됩니다.
3. **Tool (기능) 생성 탭**: 생성된 모듈에 새로운 툴(서비스/DTO) 코드를 자동으로 주입합니다. 3. **Tool (기능) 생성 탭**: 생성된 모듈에 새로운 툴 코드를 자동으로 주입합니다.
- **MCI 연동 기반 툴 생성**: 4자리 시스템 코드(예: `nclg`)를 기반으로 알맞은 패키지에 `MciNclgClient`, `Converter`, `_I`, `_O` 파일이 정확하게 생성됩니다.
### 2. CLI 스캐폴더 (기존 터미널 방식) - **완벽한 보일러플레이트 자동화**: `UseCaseImpl` 내부에 컴포넌트(`Client`, `Converter`)가 자동으로 의존성 주입되며, Java 15 Text Block을 활용해 들여쓰기(Indentation)까지 완벽히 정렬된 코드를 제공합니다.
웹 화면을 사용할 수 없는 환경이거나 터미널이 익숙한 경우, 아래 명령어를 통해 CLI 마법사를 사용할 수 있습니다.
### 2. CLI 스캐폴더 (기존 터미널 방식)
### 1⃣ 새로운 Pod(모듈) 전체를 생성할 때: `PodScaffolder` 웹 화면을 사용할 수 없는 환경이거나 터미널이 익숙한 경우, 아래 명령어를 통해 CLI 마법사를 사용할 수 있습니다.
새로운 도메인(예: 결제, HR)을 위한 완전히 독립적인 Spring Boot 모듈을 생성합니다. 폴더 구조, 빌드 스크립트, 각종 프로퍼티 및 도커 설정까지 완벽하게 세팅됩니다.
### 1⃣ 새로운 Pod(모듈) 전체를 생성할 때: `PodScaffolder`
```bash 새로운 도메인(예: 결제, HR)을 위한 완전히 독립적인 Spring Boot 모듈을 생성합니다. 폴더 구조, 빌드 스크립트, 각종 프로퍼티 및 도커 설정까지 완벽하게 세팅됩니다.
# 사용법: javac로 컴파일 후 실행
javac -encoding UTF-8 dap-common/src/main/java/io/shinhanlife/dap/common/util/PodScaffolder.java ```bash
java -cp dap-common/src/main/java io.shinhanlife.dap.common.util.PodScaffolder [모듈명] [포트번호] # 사용법: javac로 컴파일 후 실행
javac -encoding UTF-8 dap-common/src/main/java/io/shinhanlife/dap/common/util/PodScaffolder.java
# 실행 예시 (dap-tool-hr 모듈을 8086 포트로 생성) java -cp dap-common/src/main/java io.shinhanlife.dap.lib.util.PodScaffolder [모듈명] [포트번호]
java -cp dap-common/src/main/java io.shinhanlife.dap.common.util.PodScaffolder hr 8086
``` # 실행 예시 (dap-tool-hr 모듈을 8086 포트로 생성)
java -cp dap-common/src/main/java io.shinhanlife.dap.lib.util.PodScaffolder hr 8086
### 2⃣ 생성된 모듈에 새로운 툴(Function)을 추가할 때: `ToolScaffolder` ```
어노테이션(`@McpTool`, `@McpFunction`)이 완벽히 달린 Service와 입출력 DTO 코드를 지정된 모듈 패키지 룰에 맞춰 자동 생성합니다.
### 2⃣ 생성된 모듈에 새로운 툴(Function)을 추가할 때: `ToolScaffolder`
```bash 어노테이션(`@McpTool`, `@McpFunction`)이 완벽히 달린 Service와 입출력 DTO 코드를 지정된 모듈 패키지 룰에 맞춰 자동 생성합니다.
# 사용법: javac로 컴파일 후 실행
javac -encoding UTF-8 dap-common/src/main/java/io/shinhanlife/dap/common/util/ToolScaffolder.java ```bash
java -cp dap-common/src/main/java io.shinhanlife.dap.common.util.ToolScaffolder [Tool이름] [인터페이스ID] "[기능설명]" "[그룹명]" "[통신방식]" "[모듈명]" # 사용법: javac로 컴파일 후 실행
javac -encoding UTF-8 dap-common/src/main/java/io/shinhanlife/dap/common/util/ToolScaffolder.java
# 실행 예시 (payment 모듈에 결제 승인 기능 추가) java -cp dap-common/src/main/java io.shinhanlife.dap.lib.util.ToolScaffolder [Tool이름] [인터페이스ID] "[기능설명]" "[그룹명]" "[통신방식]" "[모듈명]"
java -cp dap-common/src/main/java io.shinhanlife.dap.common.util.ToolScaffolder PaymentApproval PAY_001 "결제 승인 처리 기능" "COMMON" "HTTP" "dap-tool-payment"
``` # 실행 예시 (payment 모듈에 결제 승인 기능 추가)
java -cp dap-common/src/main/java io.shinhanlife.dap.lib.util.ToolScaffolder PaymentApproval PAY_001 "결제 승인 처리 기능" "COMMON" "HTTP" "dap-tool-payment"
--- ```
## 패키지 구조 (Package Structure) ---
```text
dap-backend-main (Root)
├── dap-gateway # MCP 라우팅 허브 서버 (외부 LLM과 통신 및 Tool 분배)
├── dap-common # 공통 모듈 (Security, Session, Config 등)
├── dap-tool-core # Tool 공통 기능 (AbstractMcpToolService, Annotation, Scaffolder)
├── dap-tool-email # [Tool] 이메일 발송 특화 어댑터 모듈
├── dap-tool-sms # [Tool] SMS 발송 특화 어댑터 모듈
├── dap-tool-payment # [Tool] 결제 비즈니스 어댑터 모듈 (Scaffolded)
└── dap-tool-other # [Tool] 기타 비즈니스(청구, 계약, 고객, HR 등) 어댑터 모듈
```
*(참고: 기존 단일 모듈 프로젝트에서 마이크로서비스 확장을 위해 모듈별로 분리되었으며, 각 Tool 서버는 독립적으로 확장 및 배포할 수 있습니다.)*

View File

@@ -1,18 +1,8 @@
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY gradlew .
COPY gradle gradle
COPY build.gradle settings.gradle ./
COPY dap-tool-core dap-tool-core
COPY dap-gateway dap-gateway
RUN chmod +x gradlew
RUN ./gradlew :dap-gateway:build -x test
FROM eclipse-temurin:21-jre-alpine FROM eclipse-temurin:21-jre-alpine
WORKDIR /app WORKDIR /app
RUN apk add --no-cache tzdata RUN apk add --no-cache tzdata
ENV TZ=Asia/Seoul ENV TZ=Asia/Seoul
COPY --from=builder /app/dap-gateway/build/libs/*-SNAPSHOT.jar app.jar COPY dap-gateway/build/libs/*-SNAPSHOT.jar app.jar
EXPOSE 8081 EXPOSE 8081
ENTRYPOINT ["java", "-jar", "app.jar"] ENTRYPOINT ["java", "-jar", "app.jar"]

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg;
* @package io.shinhanlife.dap.mcg * @package io.shinhanlife.dap.mcg
* @className DapGatewayApplication * @className DapGatewayApplication
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -19,10 +19,12 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(scanBasePackages = {"io.shinhanlife.dap.mcg", "io.shinhanlife.dap.common.mcp", "io.shinhanlife.dap.common.config"}) @SpringBootApplication(scanBasePackages = {"io.shinhanlife.dap.mcg", "io.shinhanlife.dap.lib.mcp", "io.shinhanlife.dap.lib.config"})
@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dap.mcg", "io.shinhanlife.dap.common.mcp", "io.shinhanlife.dap.common.config"}) @ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dap.mcg", "io.shinhanlife.dap.lib.mcp", "io.shinhanlife.dap.lib.config"})
@EnableCaching @EnableCaching
@EnableScheduling
public class DapGatewayApplication { public class DapGatewayApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(DapGatewayApplication.class, args); SpringApplication.run(DapGatewayApplication.class, args);

View File

@@ -11,13 +11,13 @@ import org.springframework.util.StopWatch;
* @package io.shinhanlife.dap.mcg.aop * @package io.shinhanlife.dap.mcg.aop
* @className GatewayLoggingAspect * @className GatewayLoggingAspect
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.audit;
* @package io.shinhanlife.dap.mcg.audit * @package io.shinhanlife.dap.mcg.audit
* @className AuditLogService * @className AuditLogService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.config;
* @package io.shinhanlife.dap.mcg.config * @package io.shinhanlife.dap.mcg.config
* @className AgentResponseBudgetProperties * @className AgentResponseBudgetProperties
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -11,13 +11,13 @@ import java.util.Map;
* @package io.shinhanlife.dap.mcg.config * @package io.shinhanlife.dap.mcg.config
* @className GatewayFallbackProperties * @className GatewayFallbackProperties
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.config;
* @package io.shinhanlife.dap.mcg.config * @package io.shinhanlife.dap.mcg.config
* @className McpGatewayProperties * @className McpGatewayProperties
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -25,7 +25,7 @@ import java.util.stream.Collectors;
@Component @Component
@ConfigurationProperties(prefix = "mcp") @ConfigurationProperties(prefix = "mcp")
/** /**
* application.properties의 mcp.* 설정을 Java 코드에서 사용하기 위한 설정 클래스입니다. * application.yml의 mcp.* 설정을 Java 코드에서 사용하기 위한 설정 클래스입니다.
* *
* API Key, 허용 Tool, 감사 로그, Redis Trace, Retry, Circuit Breaker, * API Key, 허용 Tool, 감사 로그, Redis Trace, Retry, Circuit Breaker,
* EIMS/Tool 서버 주소 같은 MCP Gateway 운영 설정을 한 곳에서 관리합니다. * EIMS/Tool 서버 주소 같은 MCP Gateway 운영 설정을 한 곳에서 관리합니다.

View File

@@ -13,13 +13,13 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
* @package io.shinhanlife.dap.mcg.config * @package io.shinhanlife.dap.mcg.config
* @className RedisConfig * @className RedisConfig
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -4,13 +4,13 @@ package io.shinhanlife.dap.mcg.dto;
* @package io.shinhanlife.dap.mcg.dto * @package io.shinhanlife.dap.mcg.dto
* @className OperationType * @className OperationType
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -20,13 +20,13 @@ import java.util.HashSet;
* @package io.shinhanlife.dap.mcg.dto * @package io.shinhanlife.dap.mcg.dto
* @className ToolMetadata * @className ToolMetadata
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.guardrail;
* @package io.shinhanlife.dap.mcg.guardrail * @package io.shinhanlife.dap.mcg.guardrail
* @className GuardrailService * @className GuardrailService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.guardrail;
* @package io.shinhanlife.dap.mcg.guardrail * @package io.shinhanlife.dap.mcg.guardrail
* @className SensitiveDataMasker * @className SensitiveDataMasker
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.guardrail;
* @package io.shinhanlife.dap.mcg.guardrail * @package io.shinhanlife.dap.mcg.guardrail
* @className ToolResponseGuardrailService * @className ToolResponseGuardrailService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -13,13 +13,13 @@ import java.util.UUID;
* @package io.shinhanlife.dap.mcg.messaging * @package io.shinhanlife.dap.mcg.messaging
* @className KafkaProducerService * @className KafkaProducerService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.presentation;
* @package io.shinhanlife.dap.mcg.presentation * @package io.shinhanlife.dap.mcg.presentation
* @className ChatController * @className ChatController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -41,6 +41,7 @@ public class ChatController {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final RedisRegistryService registryService; private final RedisRegistryService registryService;
private final ChatClient.Builder chatClientBuilder; private final ChatClient.Builder chatClientBuilder;
private final McpRouterController mcpRouterController;
@PostMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE) @PostMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatStream(@RequestBody Map<String, String> request, public SseEmitter chatStream(@RequestBody Map<String, String> request,
@@ -54,9 +55,16 @@ public class ChatController {
try { try {
List<ToolCallback> callbacks = new ArrayList<>(); List<ToolCallback> callbacks = new ArrayList<>();
for (ToolMetadata meta : registryService.getAllTools()) { io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse toolsResponse = mcpRouterController.listTools(null).getBody();
if (Boolean.TRUE.equals(meta.getVisible())) { if (toolsResponse != null && toolsResponse.getResult() instanceof Map) {
callbacks.add(new DynamicMcpToolCallback(meta, executeService, objectMapper, effectiveTenantId)); Map<String, Object> resultMap = (Map<String, Object>) toolsResponse.getResult();
if (resultMap.containsKey("tools")) {
List<ToolMetadata> allTools = (List<ToolMetadata>) resultMap.get("tools");
for (ToolMetadata meta : allTools) {
if (Boolean.TRUE.equals(meta.getVisible())) {
callbacks.add(new DynamicMcpToolCallback(meta, executeService, objectMapper, effectiveTenantId));
}
}
} }
} }

View File

@@ -11,13 +11,13 @@ import java.util.Map;
* @package io.shinhanlife.dap.mcg.presentation * @package io.shinhanlife.dap.mcg.presentation
* @className KillSwitchController * @className KillSwitchController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,25 +5,25 @@ package io.shinhanlife.dap.mcg.presentation;
* @package io.shinhanlife.dap.mcg.presentation * @package io.shinhanlife.dap.mcg.presentation
* @className McpRouterController * @className McpRouterController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.common.adapter.dto.JsonRpcRequest; import io.shinhanlife.dap.lib.adapter.dto.JsonRpcRequest;
import io.shinhanlife.dap.common.adapter.dto.JsonRpcResponse; import io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse;
import io.shinhanlife.dap.common.adapter.dto.Params; import io.shinhanlife.dap.lib.adapter.dto.Params;
import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties; import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties;
import io.shinhanlife.dap.mcg.dto.ToolMetadata; import io.shinhanlife.dap.mcg.dto.ToolMetadata;
import io.shinhanlife.dap.mcg.registry.RedisRegistryService; import io.shinhanlife.dap.mcg.registry.RedisRegistryService;
import io.shinhanlife.dap.mcg.service.ExecuteService; import io.shinhanlife.dap.mcg.service.ExecuteService;
import io.shinhanlife.dap.common.mcp.security.SecurityProperties; import io.shinhanlife.dap.lib.mcp.security.SecurityProperties;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -91,7 +91,7 @@ public class McpRouterController {
try { try {
Object result = executeService.execute(payload, effectiveTenantId); Object result = executeService.execute(payload, effectiveTenantId);
io.shinhanlife.dap.common.adapter.dto.JsonRpcResponse response = new io.shinhanlife.dap.common.adapter.dto.JsonRpcResponse(); io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse response = new io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse();
response.setJsonrpc("2.0"); response.setJsonrpc("2.0");
response.setId(payload.containsKey("id") ? String.valueOf(payload.get("id")) : UUID.randomUUID().toString()); response.setId(payload.containsKey("id") ? String.valueOf(payload.get("id")) : UUID.randomUUID().toString());
response.setResult(result); response.setResult(result);
@@ -112,9 +112,7 @@ public class McpRouterController {
} }
} }
@GetMapping("/tools/list") private List<ToolMetadata> fetchAllActiveTools() {
public ResponseEntity<JsonRpcResponse> listTools(
@RequestParam(value = "categoryKey", required = false) String categoryKey) {
List<ToolMetadata> activeTools = redisRegistryService.getAllTools() List<ToolMetadata> activeTools = redisRegistryService.getAllTools()
.stream() .stream()
.filter(ToolMetadata::getVisible) .filter(ToolMetadata::getVisible)
@@ -148,6 +146,14 @@ public class McpRouterController {
log.warn("Failed to fetch local tools from fallback URL: {}", url); log.warn("Failed to fetch local tools from fallback URL: {}", url);
} }
} }
return activeTools;
}
@GetMapping("/tools/list")
public ResponseEntity<JsonRpcResponse> listTools(
@RequestParam(value = "categoryKey", required = false) String categoryKey) {
List<ToolMetadata> activeTools = fetchAllActiveTools();
if (categoryKey != null && !categoryKey.trim().isEmpty()) { if (categoryKey != null && !categoryKey.trim().isEmpty()) {
activeTools = activeTools.stream() activeTools = activeTools.stream()
@@ -161,12 +167,10 @@ public class McpRouterController {
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} }
@GetMapping(value = "/tools/docs/markdown", produces = "text/markdown;charset=UTF-8") @GetMapping(value = "/tools/docs/markdown", produces = "text/markdown;charset=UTF-8")
public ResponseEntity<String> generateToolsMarkdown() { public ResponseEntity<String> generateToolsMarkdown() {
List<ToolMetadata> tools = redisRegistryService.getAllTools() List<ToolMetadata> tools = fetchAllActiveTools();
.stream()
.filter(ToolMetadata::getVisible)
.collect(Collectors.toList());
StringBuilder md = new StringBuilder(); StringBuilder md = new StringBuilder();
md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n"); md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n");

View File

@@ -5,19 +5,19 @@ package io.shinhanlife.dap.mcg.presentation;
* @package io.shinhanlife.dap.mcg.presentation * @package io.shinhanlife.dap.mcg.presentation
* @className ScaffoldingController * @className ScaffoldingController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
import io.shinhanlife.dap.common.util.PodScaffolder; import io.shinhanlife.dap.lib.util.PodScaffolder;
import io.shinhanlife.dap.common.util.ToolScaffolder; import io.shinhanlife.dap.lib.util.ToolScaffolder;
import io.shinhanlife.dap.common.util.ToolSourceUpdater; import io.shinhanlife.dap.lib.util.ToolSourceUpdater;
import java.io.File; import java.io.File;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -34,7 +34,7 @@ public class ScaffoldingController {
@PostMapping("/pod") @PostMapping("/pod")
public String scaffoldPod(@RequestBody Map<String, String> req) { public String scaffoldPod(@RequestBody Map<String, String> req) {
try { try {
String moduleName = req.getOrDefault("moduleName", "dap-tool-other"); String moduleName = req.getOrDefault("moduleName", "dap-tool-oth");
if (!moduleName.startsWith("dap-tool-")) moduleName = "dap-tool-" + moduleName; if (!moduleName.startsWith("dap-tool-")) moduleName = "dap-tool-" + moduleName;
String port = req.getOrDefault("port", "8085"); String port = req.getOrDefault("port", "8085");
String shortName = moduleName.replace("dap-tool-", "").replace("-", ""); String shortName = moduleName.replace("dap-tool-", "").replace("-", "");
@@ -57,14 +57,15 @@ public class ScaffoldingController {
String description = req.get("description"); String description = req.get("description");
String group = req.getOrDefault("categoryKey", req.getOrDefault("group", "COMMON")); String group = req.getOrDefault("categoryKey", req.getOrDefault("group", "COMMON"));
String routingType = req.getOrDefault("routingType", "HTTP"); String routingType = req.getOrDefault("routingType", "HTTP");
String moduleName = req.getOrDefault("moduleName", "dap-tool-other"); String moduleName = req.getOrDefault("moduleName", "dap-tool-oth");
String author = req.get("author"); String author = req.get("author");
if (author == null || author.trim().isEmpty()) author = System.getProperty("user.name"); if (author == null || author.trim().isEmpty()) author = System.getProperty("user.name");
String date = req.get("date"); String date = req.get("date");
if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true")); boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
String clientSystemCode = req.get("clientSystemCode");
return ToolScaffolder.scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, date, register); return ToolScaffolder.scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, date, register, clientSystemCode);
} catch (Exception e) { } catch (Exception e) {
return "오류 발생: " + e.getMessage(); return "오류 발생: " + e.getMessage();
} }
@@ -96,12 +97,12 @@ public class ScaffoldingController {
File[] files = dir.listFiles(f -> f.isDirectory() && f.getName().startsWith("dap-tool-") && !f.getName().equals("dap-tool-core")); File[] files = dir.listFiles(f -> f.isDirectory() && f.getName().startsWith("dap-tool-") && !f.getName().equals("dap-tool-core"));
if (files == null || files.length == 0) { if (files == null || files.length == 0) {
return List.of("dap-tool-other", "dap-tool-email", "dap-tool-hr", "dap-tool-payment", "dap-tool-sms"); return List.of("dap-tool-oth", "dap-tool-hr", "dap-tool-sms");
} }
return Arrays.stream(files).map(File::getName).sorted().collect(Collectors.toList()); return Arrays.stream(files).map(File::getName).sorted().collect(Collectors.toList());
} catch (Exception e) { } catch (Exception e) {
return List.of("dap-tool-other", "dap-tool-email", "dap-tool-hr", "dap-tool-payment", "dap-tool-sms"); return List.of("dap-tool-oth", "dap-tool-hr", "dap-tool-sms");
} }
} }
} }

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.redis;
* @package io.shinhanlife.dap.mcg.redis * @package io.shinhanlife.dap.mcg.redis
* @className McpMonitorEventService * @className McpMonitorEventService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.redis;
* @package io.shinhanlife.dap.mcg.redis * @package io.shinhanlife.dap.mcg.redis
* @className RedisToolTraceService * @className RedisToolTraceService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -16,13 +16,13 @@ import java.util.Objects;
* @package io.shinhanlife.dap.mcg.registry * @package io.shinhanlife.dap.mcg.registry
* @className RedisRegistryService * @className RedisRegistryService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className CircuitBreaker * @className CircuitBreaker
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className CircuitBreakerMonitorController * @className CircuitBreakerMonitorController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className CircuitBreakerService * @className CircuitBreakerService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className CircuitBreakerSnapshot * @className CircuitBreakerSnapshot
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className CircuitBreakerState * @className CircuitBreakerState
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className FailureType * @className FailureType
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className RetryPolicy * @className RetryPolicy
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.resilience;
* @package io.shinhanlife.dap.mcg.resilience * @package io.shinhanlife.dap.mcg.resilience
* @className ToolExecutionException * @className ToolExecutionException
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.security;
* @package io.shinhanlife.dap.mcg.security * @package io.shinhanlife.dap.mcg.security
* @className McpRequestContext * @className McpRequestContext
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.security;
* @package io.shinhanlife.dap.mcg.security * @package io.shinhanlife.dap.mcg.security
* @className McpRequestContextResolver * @className McpRequestContextResolver
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.security;
* @package io.shinhanlife.dap.mcg.security * @package io.shinhanlife.dap.mcg.security
* @className ToolAuthorizationService * @className ToolAuthorizationService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.service;
* @package io.shinhanlife.dap.mcg.service * @package io.shinhanlife.dap.mcg.service
* @className ExecuteService * @className ExecuteService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -9,13 +9,13 @@ import org.springframework.stereotype.Service;
* @package io.shinhanlife.dap.mcg.service * @package io.shinhanlife.dap.mcg.service
* @className KillSwitchService * @className KillSwitchService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,6 +1,6 @@
package io.shinhanlife.dap.mcg.service; package io.shinhanlife.dap.mcg.service;
import io.shinhanlife.dap.common.mcp.security.SecurityProperties; import io.shinhanlife.dap.lib.mcp.security.SecurityProperties;
import io.shinhanlife.dap.mcg.registry.RedisRegistryService; import io.shinhanlife.dap.mcg.registry.RedisRegistryService;
import io.shinhanlife.dap.mcg.dto.ToolMetadata; import io.shinhanlife.dap.mcg.dto.ToolMetadata;
import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties; import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties;
@@ -15,13 +15,13 @@ import java.util.Map;
* @package io.shinhanlife.dap.mcg.service * @package io.shinhanlife.dap.mcg.service
* @className ToolPlanner * @className ToolPlanner
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -4,13 +4,13 @@ package io.shinhanlife.dap.mcg.sync;
* @package io.shinhanlife.dap.mcg.sync * @package io.shinhanlife.dap.mcg.sync
* @className CustomWebMvcSseServerTransportProvider * @className CustomWebMvcSseServerTransportProvider
* @description AX HUB MCP Gateway SSE 전송 제공자 - SSE 기반의 MCP 서버 트랜스포트를 구현하는 클래스 * @description AX HUB MCP Gateway SSE 전송 제공자 - SSE 기반의 MCP 서버 트랜스포트를 구현하는 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -95,8 +95,8 @@ public class CustomWebMvcSseServerTransportProvider implements McpServerTranspor
McpServerSession session = sessionFactory.create(sessionTransport); McpServerSession session = sessionFactory.create(sessionTransport);
sessions.put(sessionId, session); sessions.put(sessionId, session);
emitter.onCompletion(() -> sessions.remove(sessionId)); // emitter.onCompletion(() -> sessions.remove(sessionId));
emitter.onTimeout(() -> sessions.remove(sessionId)); // emitter.onTimeout(() -> sessions.remove(sessionId));
new Thread(() -> { new Thread(() -> {
try { try {
@@ -179,8 +179,8 @@ public class CustomWebMvcSseServerTransportProvider implements McpServerTranspor
log.info("Message sent to session handler"); log.info("Message sent to session handler");
if (emitter != null && !map.containsKey("id")) { if (emitter != null && !map.containsKey("id")) {
emitter.complete(); // emitter.complete();
log.info("Completed emitter for notification"); log.info("Completed emitter for notification (disabled for keep-alive)");
} }
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
@@ -220,7 +220,7 @@ public class CustomWebMvcSseServerTransportProvider implements McpServerTranspor
// Custom 프로토콜: 1회 요청당 1응답 후 종료 (스트림을 닫아버림) // Custom 프로토콜: 1회 요청당 1응답 후 종료 (스트림을 닫아버림)
// 클라이언트가 한 번의 POST 후 응답을 받고 연결을 끊기 때문 // 클라이언트가 한 번의 POST 후 응답을 받고 연결을 끊기 때문
this.emitter.complete(); // this.emitter.complete();
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Error sending message to SSE emitter", e); log.error("Error sending message to SSE emitter", e);

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.sync;
* @package io.shinhanlife.dap.mcg.sync * @package io.shinhanlife.dap.mcg.sync
* @className DynamicMcpController * @className DynamicMcpController
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -84,4 +84,19 @@ public class DynamicMcpController {
.header("Mcp-Session-Id", activeSessionId) .header("Mcp-Session-Id", activeSessionId)
.body(emitter); .body(emitter);
} }
@org.springframework.web.bind.annotation.DeleteMapping("/mcp/sse/{category}")
public ResponseEntity<Void> handleDeleteSse(@PathVariable("category") String category) {
return ResponseEntity.ok().build();
}
@GetMapping("/.well-known/oauth-protected-resource")
public ResponseEntity<java.util.Map<String, Object>> handleOauthProtectedResource() {
return ResponseEntity.ok().body(java.util.Map.of());
}
@GetMapping("/.well-known/oauth-protected-resource/**")
public ResponseEntity<java.util.Map<String, Object>> handleOauthProtectedResourceWildcard() {
return ResponseEntity.ok().body(java.util.Map.of());
}
} }

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.sync;
* @package io.shinhanlife.dap.mcg.sync * @package io.shinhanlife.dap.mcg.sync
* @className DynamicMcpServerManager * @className DynamicMcpServerManager
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -53,7 +53,7 @@ public class DynamicMcpServerManager {
getOrCreateServer("payment"); getOrCreateServer("payment");
getOrCreateServer("sms"); getOrCreateServer("sms");
getOrCreateServer("email"); getOrCreateServer("email");
getOrCreateServer("other"); getOrCreateServer("oth");
getOrCreateServer("sample"); getOrCreateServer("sample");
} }

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.sync;
* @package io.shinhanlife.dap.mcg.sync * @package io.shinhanlife.dap.mcg.sync
* @className RegistryMcpToolSpecificationFactory * @className RegistryMcpToolSpecificationFactory
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -22,13 +22,13 @@ import java.util.stream.Collectors;
* @package io.shinhanlife.dap.mcg.sync * @package io.shinhanlife.dap.mcg.sync
* @className RegistryMcpToolSynchronizer * @className RegistryMcpToolSynchronizer
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.large;
* @package io.shinhanlife.dap.mcg.tool.large * @package io.shinhanlife.dap.mcg.tool.large
* @className AgentResponseBudgetService * @className AgentResponseBudgetService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.large;
* @package io.shinhanlife.dap.mcg.tool.large * @package io.shinhanlife.dap.mcg.tool.large
* @className LargeToolResponseService * @className LargeToolResponseService
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.large;
* @package io.shinhanlife.dap.mcg.tool.large * @package io.shinhanlife.dap.mcg.tool.large
* @className PaginationRequestValidator * @className PaginationRequestValidator
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.result;
* @package io.shinhanlife.dap.mcg.tool.result * @package io.shinhanlife.dap.mcg.tool.result
* @className ToolExecutionResult * @className ToolExecutionResult
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.result;
* @package io.shinhanlife.dap.mcg.tool.result * @package io.shinhanlife.dap.mcg.tool.result
* @className ToolExecutionResultFormatter * @className ToolExecutionResultFormatter
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.transport;
* @package io.shinhanlife.dap.mcg.transport * @package io.shinhanlife.dap.mcg.transport
* @className HttpToolInvoker * @className HttpToolInvoker
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.transport;
* @package io.shinhanlife.dap.mcg.transport * @package io.shinhanlife.dap.mcg.transport
* @className ToolInvoker * @className ToolInvoker
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,37 +0,0 @@
package io.shinhanlife.dap.sample.converter;
import io.shinhanlife.dap.sample.domain.model.AppliSystNtfyPatiModel;
import io.shinhanlife.dap.sample.dto.AppliSystNtfyRgiInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListOutDTO;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiRequest;
import io.shinhanlife.dap.sample.presentation.io.StrnTermRequest;
import io.shinhanlife.dap.sample.presentation.io.StrnTermResponse;
import org.mapstruct.Mapper;
/**
* @package io.shinhanlife.dap.sample.converter
* @className SampleConverter
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Mapper(componentModel = "spring")
public abstract class SampleConverter {
public abstract StrnTermListInDTO convertRequestToDto(StrnTermRequest req);
public abstract StrnTermResponse convertDtoToResponse(StrnTermListOutDTO outDto);
public abstract AppliSystNtfyPatiModel convertDtoToModel(AppliSystNtfyRgiInDTO inDto);
public abstract AppliSystNtfyRgiInDTO convertAppliRequestToDto(AppliSystNtfyPatiRequest request);
}

View File

@@ -1,35 +0,0 @@
package io.shinhanlife.dap.sample.domain.model;
import io.shinhanlife.glow.db.dto.AuditInfo;
import lombok.*;
/**
* @package io.shinhanlife.dap.sample.domain.model
* @className AppliSystNtfyPatiModel
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class AppliSystNtfyPatiModel extends AuditInfo {
private String appliSystNtfyPatiId;
private String appliSystNtfyKdCd;
private String appliDutjCd;
private String appliDutjPrjcCd;
private String ntfyMsgCt;
private String ntfyOccDt;
private String ntfyCfmDt;
private String ntfyTrgtPrafNo;
private String shmsPmlYn;
private String ntfyCfmYn;
}

View File

@@ -1,34 +0,0 @@
package io.shinhanlife.dap.sample.domain.repository;
import io.shinhanlife.dap.sample.domain.model.AppliSystNtfyPatiModel;
import io.shinhanlife.dap.sample.dto.StrnTermListInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListOutDTO;
import io.shinhanlife.glow.GlowIndexPaging;
import io.shinhanlife.glow.GlowMybatisMapper;
import io.shinhanlife.glow.PageInfo;
import java.util.List;
/**
* @package io.shinhanlife.dap.sample.domain.repository
* @className GlowSampleRepository
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@GlowMybatisMapper
public interface GlowSampleRepository {
@GlowIndexPaging
List<StrnTermListOutDTO.StrnTerm> selectStrnTerm(StrnTermListInDTO inDto, PageInfo pageInfo);
int insertAppliSystNtfyPati(AppliSystNtfyPatiModel appliSystNtfyPatiModel);
}

View File

@@ -1,25 +0,0 @@
package io.shinhanlife.dap.sample.domain.service;
import io.shinhanlife.dap.sample.dto.AppliSystNtfyRgiInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListOutDTO;
import io.shinhanlife.glow.PageInfo;
/**
* @package io.shinhanlife.dap.sample.domain.service
* @className GlowSampleService
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
public interface GlowSampleService {
StrnTermListOutDTO getStrnTerms(StrnTermListInDTO inDto, PageInfo pageInfo);
int insertAppliSystNtfyPati(AppliSystNtfyRgiInDTO inDto);
}

View File

@@ -1,55 +0,0 @@
package io.shinhanlife.dap.sample.domain.service.impl;
import io.shinhanlife.dap.sample.converter.SampleConverter;
import io.shinhanlife.dap.sample.domain.model.AppliSystNtfyPatiModel;
import io.shinhanlife.dap.sample.domain.repository.GlowSampleRepository;
import io.shinhanlife.dap.sample.domain.service.GlowSampleService;
import io.shinhanlife.dap.sample.dto.AppliSystNtfyRgiInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListInDTO;
import io.shinhanlife.dap.sample.dto.StrnTermListOutDTO;
import io.shinhanlife.glow.GlowLogger;
import io.shinhanlife.glow.GlowLogTarget;
import io.shinhanlife.glow.PageInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @package io.shinhanlife.dap.sample.domain.service.impl
* @className GlowSampleServiceImpl
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Service
@RequiredArgsConstructor
public class GlowSampleServiceImpl implements GlowSampleService {
@GlowLogTarget(GlowLogTarget.Target.FILE)
private final GlowLogger log;
private final GlowSampleRepository glowSampleRepository;
private final SampleConverter sampleConverter;
@Override
public StrnTermListOutDTO getStrnTerms(StrnTermListInDTO inDto, PageInfo pageInfo) {
List<StrnTermListOutDTO.StrnTerm> out = glowSampleRepository.selectStrnTerm(inDto, pageInfo);
return StrnTermListOutDTO.builder()
.strnTerms(out)
.pageInfo(pageInfo)
.build();
}
@Override
public int insertAppliSystNtfyPati(AppliSystNtfyRgiInDTO inDto) {
AppliSystNtfyPatiModel appliSystNtfyPatiModel = sampleConverter.convertDtoToModel(inDto);
return glowSampleRepository.insertAppliSystNtfyPati(appliSystNtfyPatiModel);
}
}

View File

@@ -1,41 +0,0 @@
package io.shinhanlife.dap.sample.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.*;
/**
* @package io.shinhanlife.dap.sample.dto
* @className AppliSystNtfyRgiInDTO
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AppliSystNtfyRgiInDTO {
private String appliSystNtfyPatiId;
private String appliSystNtfyKdCd;
private String appliDutjCd;
private String appliDutjPrjcCd;
private String ntfyMsgCt;
private String ntfyOccDt;
private String ntfyCfmDt;
private String ntfyTrgtPrafNo;
private String shmsPmlYn;
private String ntfyCfmYn;
}

View File

@@ -1,31 +0,0 @@
package io.shinhanlife.dap.sample.dto;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
/**
* @package io.shinhanlife.dap.sample.dto
* @className StrnTermListInDTO
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StrnTermListInDTO {
private String strnTermHanNm;
}

View File

@@ -1,46 +0,0 @@
package io.shinhanlife.dap.sample.dto;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import io.shinhanlife.glow.PageInfo;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @package io.shinhanlife.dap.sample.dto
* @className StrnTermListOutDTO
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class StrnTermListOutDTO {
private List<StrnTerm> strnTerms;
private PageInfo pageInfo;
@Builder
@Getter
@Setter
public static class StrnTerm{
private String strnTermHanNm;
private String strnTermEngcAbrNm;
private String strnTermEngNm;
private String strnTermScrnTermNm;
}
}

View File

@@ -1,52 +0,0 @@
package io.shinhanlife.dap.sample.presentation;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiRequest;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiResponse;
import io.shinhanlife.dap.sample.presentation.io.StrnTermRequest;
import io.shinhanlife.dap.sample.presentation.io.StrnTermResponse;
import io.shinhanlife.dap.sample.usecase.GlowSampleUseCase;
import io.shinhanlife.glow.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @package io.shinhanlife.dap.sample.presentation
* @className GlowSampleController
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@RestController
@RequiredArgsConstructor
public class GlowSampleController {
@GlowLogTarget({GlowLogTarget.Target.CONSOLE, GlowLogTarget.Target.FILE})
private final GlowLogger log;
private final GlowSampleUseCase glowSampleUseCase;
@GlowControllerId(value = "selectStrnTerm")
@PostMapping("/selectStrnTerm")
public ResponseEntity<BaseResponse<StrnTermResponse>> getStrnTerms(@RequestBody StrnTermRequest request) {
return ResponseUtil.ok(glowSampleUseCase.getStrnTerms(request));
}
@GlowControllerId(value = "insertAp")
@PostMapping("/insertAppliSystNtfyPati")
public ResponseEntity<BaseResponse<AppliSystNtfyPatiResponse>> insertAppliSystNtfyPati(@RequestBody AppliSystNtfyPatiRequest request) {
return ResponseUtil.ok(glowSampleUseCase.insertAppliSystNtfyPati(request));
}
}

View File

@@ -1,34 +0,0 @@
package io.shinhanlife.dap.sample.presentation.io;
import lombok.*;
/**
* @package io.shinhanlife.dap.sample.presentation.io
* @className AppliSystNtfyPatiRequest
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class AppliSystNtfyPatiRequest {
private String appliSystNtfyPatiId;
private String appliSystNtfyKdCd;
private String appliDutjCd;
private String appliDutjPrjcCd;
private String ntfyMsgCt;
private String ntfyOccDt;
private String ntfyCfmDt;
private String ntfyTrgtPrafNo;
private String shmsPmlYn;
private String ntfyCfmYn;
}

View File

@@ -1,26 +0,0 @@
package io.shinhanlife.dap.sample.presentation.io;
import lombok.*;
/**
* @package io.shinhanlife.dap.sample.presentation.io
* @className AppliSystNtfyPatiResponse
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class AppliSystNtfyPatiResponse {
private String successYn;
private String msg;
}

View File

@@ -1,28 +0,0 @@
package io.shinhanlife.dap.sample.presentation.io;
import io.shinhanlife.glow.PageInfo;
import lombok.*;
/**
* @package io.shinhanlife.dap.sample.presentation.io
* @className StrnTermRequest
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class StrnTermRequest {
private PageInfo pageInfo;
private String strnTermHanNm;
}

View File

@@ -1,41 +0,0 @@
package io.shinhanlife.dap.sample.presentation.io;
import io.shinhanlife.glow.PageInfo;
import lombok.*;
import java.util.List;
/**
* @package io.shinhanlife.dap.sample.presentation.io
* @className StrnTermResponse
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class StrnTermResponse {
private List<StrnTerm> strnTerms;
private PageInfo pageInfo;
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class StrnTerm{
private String strnTermHanNm;
private String strnTermEngcAbrNm;
private String strnTermEngNm;
private String strnTermScrnTermNm;
}
}

View File

@@ -1,25 +0,0 @@
package io.shinhanlife.dap.sample.usecase;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiRequest;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiResponse;
import io.shinhanlife.dap.sample.presentation.io.StrnTermRequest;
import io.shinhanlife.dap.sample.presentation.io.StrnTermResponse;
/**
* @package io.shinhanlife.dap.sample.usecase
* @className GlowSampleUseCase
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
public interface GlowSampleUseCase {
StrnTermResponse getStrnTerms(StrnTermRequest req);
AppliSystNtfyPatiResponse insertAppliSystNtfyPati(AppliSystNtfyPatiRequest req);
}

View File

@@ -1,57 +0,0 @@
package io.shinhanlife.dap.sample.usecase.impl;
import io.shinhanlife.dap.sample.converter.SampleConverter;
import io.shinhanlife.dap.sample.domain.service.GlowSampleService;
import io.shinhanlife.dap.sample.dto.StrnTermListOutDTO;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiRequest;
import io.shinhanlife.dap.sample.presentation.io.AppliSystNtfyPatiResponse;
import io.shinhanlife.dap.sample.presentation.io.StrnTermRequest;
import io.shinhanlife.dap.sample.presentation.io.StrnTermResponse;
import io.shinhanlife.dap.sample.usecase.GlowSampleUseCase;
import io.shinhanlife.glow.GlowAppServiceId;
import io.shinhanlife.glow.GlowLogTarget;
import io.shinhanlife.glow.GlowLogger;
import io.shinhanlife.glow.GlowServiceGroupId;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* @package io.shinhanlife.dap.sample.usecase.impl
* @className GlowSampleUseCaseImpl
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
@Service
@RequiredArgsConstructor
@GlowServiceGroupId(value = "GlowSample", description="GlowSampleUseCase")
public class GlowSampleUseCaseImpl implements GlowSampleUseCase {
@GlowLogTarget(GlowLogTarget.Target.FILE)
private final GlowLogger log;
private final GlowSampleService glowSampleService;
private final SampleConverter converter;
@GlowAppServiceId(value = "SAMPLE-DB-0001", description = "표준용어조회(DB)")
public StrnTermResponse getStrnTerms(StrnTermRequest req) {
StrnTermListOutDTO outDto = glowSampleService.getStrnTerms(converter.convertRequestToDto(req), req.getPageInfo());
return converter.convertDtoToResponse(outDto);
}
@GlowAppServiceId(value = "SAMPLE-DB-0002", description = "어플리케이션시스템알림내역등록")
public AppliSystNtfyPatiResponse insertAppliSystNtfyPati(AppliSystNtfyPatiRequest req) {
int rtn = glowSampleService.insertAppliSystNtfyPati(converter.convertAppliRequestToDto(req));
return AppliSystNtfyPatiResponse.builder()
.successYn(rtn > 0 ? "Y" : "N")
.msg(rtn > 0 ? "성공적으로 처리 되었습니다." : "처리중 오류발생!!")
.build();
}
}

View File

@@ -1,160 +0,0 @@
-- ============================================================
-- AX HUB 역할-Tool/지식 권한 관리 DDL
-- 대상 스키마 : 프로젝트 AP 스키마 (S_EIAM_TIS 는 읽기전용 참조)
-- 작성일 : 2026-06-25
-- ============================================================
-- ① Tool 마스터
CREATE TABLE AX_TOOL_MST (
TOOL_ID VARCHAR(20) NOT NULL, -- Tool ID (PK)
TOOL_NM VARCHAR(100) NOT NULL, -- Tool명
TOOL_DS VARCHAR(500), -- Tool설명
TOOL_TYPE_CD VARCHAR(20), -- Tool유형코드 (MCP / FUNC / EXT)
PUSE_YN VARCHAR(1) DEFAULT 'Y',-- 사용여부
SYST_RGI_DT DATE,
SYST_RGI_PRAF_NO VARCHAR(8),
SYST_RGI_OGNZ_NO VARCHAR(7),
SYST_RGI_SYST_CD VARCHAR(3),
SYST_RGI_PRGR_ID VARCHAR(100),
SYST_CHG_DT DATE,
SYST_CHG_PRAF_NO VARCHAR(8),
SYST_CHG_OGNZ_NO VARCHAR(7),
SYST_CHG_SYST_CD VARCHAR(3),
SYST_CHG_PRGR_ID VARCHAR(100),
CONSTRAINT PK_AX_TOOL_MST PRIMARY KEY (TOOL_ID)
);
COMMENT ON TABLE AX_TOOL_MST IS 'AX HUB Tool 마스터';
COMMENT ON COLUMN AX_TOOL_MST.TOOL_ID IS 'Tool ID (PK)';
COMMENT ON COLUMN AX_TOOL_MST.TOOL_NM IS 'Tool명';
COMMENT ON COLUMN AX_TOOL_MST.TOOL_DS IS 'Tool설명';
COMMENT ON COLUMN AX_TOOL_MST.TOOL_TYPE_CD IS 'Tool유형코드 (MCP/FUNC/EXT)';
COMMENT ON COLUMN AX_TOOL_MST.PUSE_YN IS '사용여부 (Y/N)';
-- ② 지식(Knowledge) 마스터
CREATE TABLE AX_KNWL_MST (
KNWL_ID VARCHAR(20) NOT NULL, -- 지식 ID (PK)
KNWL_NM VARCHAR(100) NOT NULL, -- 지식명
KNWL_DS VARCHAR(500), -- 지식설명
KNWL_TYPE_CD VARCHAR(20), -- 지식유형코드 (PRODUCT/MANUAL/LEGAL 등)
PUSE_YN VARCHAR(1) DEFAULT 'Y',
SYST_RGI_DT DATE,
SYST_RGI_PRAF_NO VARCHAR(8),
SYST_RGI_OGNZ_NO VARCHAR(7),
SYST_RGI_SYST_CD VARCHAR(3),
SYST_RGI_PRGR_ID VARCHAR(100),
SYST_CHG_DT DATE,
SYST_CHG_PRAF_NO VARCHAR(8),
SYST_CHG_OGNZ_NO VARCHAR(7),
SYST_CHG_SYST_CD VARCHAR(3),
SYST_CHG_PRGR_ID VARCHAR(100),
CONSTRAINT PK_AX_KNWL_MST PRIMARY KEY (KNWL_ID)
);
COMMENT ON TABLE AX_KNWL_MST IS 'AX HUB 지식 마스터';
COMMENT ON COLUMN AX_KNWL_MST.KNWL_ID IS '지식 ID (PK)';
COMMENT ON COLUMN AX_KNWL_MST.KNWL_NM IS '지식명';
COMMENT ON COLUMN AX_KNWL_MST.KNWL_DS IS '지식설명';
COMMENT ON COLUMN AX_KNWL_MST.KNWL_TYPE_CD IS '지식유형코드 (PRODUCT/MANUAL/LEGAL/REPORT)';
COMMENT ON COLUMN AX_KNWL_MST.PUSE_YN IS '사용여부 (Y/N)';
-- ③ 역할-Tool 권한 매핑
-- SYST_ID + ROLE_NO → S_EIAM_TIS.AA_ROLE 참조 (FK 미설정: 스키마 분리 환경)
CREATE TABLE AX_ROLE_TOOL_ATHR (
ROLE_TOOL_ATHR_ID VARCHAR(20) NOT NULL, -- 역할Tool권한ID (PK)
SYST_ID VARCHAR(10) NOT NULL, -- 시스템ID (EIAM 연동 키)
ROLE_NO VARCHAR(50) NOT NULL, -- 역할번호 (EIAM AA_ROLE.ROLE_NO)
TOOL_ID VARCHAR(20) NOT NULL, -- Tool ID
PUSE_YN VARCHAR(1) DEFAULT 'Y',
SYST_RGI_DT DATE,
SYST_RGI_PRAF_NO VARCHAR(8),
SYST_RGI_OGNZ_NO VARCHAR(7),
SYST_RGI_SYST_CD VARCHAR(3),
SYST_RGI_PRGR_ID VARCHAR(100),
SYST_CHG_DT DATE,
SYST_CHG_PRAF_NO VARCHAR(8),
SYST_CHG_OGNZ_NO VARCHAR(7),
SYST_CHG_SYST_CD VARCHAR(3),
SYST_CHG_PRGR_ID VARCHAR(100),
CONSTRAINT PK_AX_ROLE_TOOL_ATHR PRIMARY KEY (ROLE_TOOL_ATHR_ID)
);
-- (SYST_ID, ROLE_NO, TOOL_ID) 중복 방지
CREATE UNIQUE INDEX UK_AX_ROLE_TOOL_ATHR
ON AX_ROLE_TOOL_ATHR (SYST_ID, ROLE_NO, TOOL_ID);
COMMENT ON TABLE AX_ROLE_TOOL_ATHR IS '역할-Tool 권한 매핑';
COMMENT ON COLUMN AX_ROLE_TOOL_ATHR.ROLE_TOOL_ATHR_ID IS '역할Tool권한ID (PK)';
COMMENT ON COLUMN AX_ROLE_TOOL_ATHR.SYST_ID IS '시스템ID';
COMMENT ON COLUMN AX_ROLE_TOOL_ATHR.ROLE_NO IS '역할번호 (EIAM)';
COMMENT ON COLUMN AX_ROLE_TOOL_ATHR.TOOL_ID IS 'Tool ID';
COMMENT ON COLUMN AX_ROLE_TOOL_ATHR.PUSE_YN IS '사용여부';
-- ④ 역할-지식 권한 매핑
CREATE TABLE AX_ROLE_KNWL_ATHR (
ROLE_KNWL_ATHR_ID VARCHAR(20) NOT NULL, -- 역할지식권한ID (PK)
SYST_ID VARCHAR(10) NOT NULL,
ROLE_NO VARCHAR(50) NOT NULL,
KNWL_ID VARCHAR(20) NOT NULL,
PUSE_YN VARCHAR(1) DEFAULT 'Y',
SYST_RGI_DT DATE,
SYST_RGI_PRAF_NO VARCHAR(8),
SYST_RGI_OGNZ_NO VARCHAR(7),
SYST_RGI_SYST_CD VARCHAR(3),
SYST_RGI_PRGR_ID VARCHAR(100),
SYST_CHG_DT DATE,
SYST_CHG_PRAF_NO VARCHAR(8),
SYST_CHG_OGNZ_NO VARCHAR(7),
SYST_CHG_SYST_CD VARCHAR(3),
SYST_CHG_PRGR_ID VARCHAR(100),
CONSTRAINT PK_AX_ROLE_KNWL_ATHR PRIMARY KEY (ROLE_KNWL_ATHR_ID)
);
CREATE UNIQUE INDEX UK_AX_ROLE_KNWL_ATHR
ON AX_ROLE_KNWL_ATHR (SYST_ID, ROLE_NO, KNWL_ID);
COMMENT ON TABLE AX_ROLE_KNWL_ATHR IS '역할-지식 권한 매핑';
COMMENT ON COLUMN AX_ROLE_KNWL_ATHR.ROLE_KNWL_ATHR_ID IS '역할지식권한ID (PK)';
COMMENT ON COLUMN AX_ROLE_KNWL_ATHR.SYST_ID IS '시스템ID';
COMMENT ON COLUMN AX_ROLE_KNWL_ATHR.ROLE_NO IS '역할번호 (EIAM)';
COMMENT ON COLUMN AX_ROLE_KNWL_ATHR.KNWL_ID IS '지식ID';
COMMENT ON COLUMN AX_ROLE_KNWL_ATHR.PUSE_YN IS '사용여부';
-- ============================================================
-- 샘플 데이터 (개발용)
-- ============================================================
INSERT INTO AX_TOOL_MST
(TOOL_ID, TOOL_NM, TOOL_DS, TOOL_TYPE_CD, PUSE_YN,
SYST_RGI_DT, SYST_RGI_PRAF_NO, SYST_RGI_OGNZ_NO, SYST_RGI_SYST_CD, SYST_RGI_PRGR_ID,
SYST_CHG_DT, SYST_CHG_PRAF_NO, SYST_CHG_OGNZ_NO, SYST_CHG_SYST_CD, SYST_CHG_PRGR_ID)
VALUES
('TOOL_A', '지식 검색', '지식베이스 내 문서 의미 기반 검색', 'MCP', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100'),
('TOOL_B', 'DB 조회', '사내 데이터베이스 직접 조회 (GLOW)', 'MCP', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100'),
('TOOL_C', '문서 생성', 'AI 기반 문서 초안 자동 생성', 'FUNC', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100');
INSERT INTO AX_KNWL_MST
(KNWL_ID, KNWL_NM, KNWL_DS, KNWL_TYPE_CD, PUSE_YN,
SYST_RGI_DT, SYST_RGI_PRAF_NO, SYST_RGI_OGNZ_NO, SYST_RGI_SYST_CD, SYST_RGI_PRGR_ID,
SYST_CHG_DT, SYST_CHG_PRAF_NO, SYST_CHG_OGNZ_NO, SYST_CHG_SYST_CD, SYST_CHG_PRGR_ID)
VALUES
('KNWL_Q', '상품기초서류', '보험 상품 기초서류 약 8만건', 'PRODUCT', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100'),
('KNWL_W', '업무매뉴얼', '내부 업무 매뉴얼 및 프로세스 가이드', 'MANUAL', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100'),
('KNWL_E', '법률/규정', '보험업법 및 금융당국 규정', 'LEGAL', 'Y',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100',
CURRENT_DATE, 'SYSTEM', 'SYSTEM', 'AXH', 'SOATM0100');
COMMIT;

View File

@@ -1,19 +0,0 @@
# Dev 환경 전용 설정 (개발 서버 DB 연결 정보 등)
# spring.datasource.url=jdbc:oracle:thin:@//dev-db-host:1521/XEPDB1
# spring.datasource.driverClassName=oracle.jdbc.OracleDriver
# spring.datasource.username=dev_user
# spring.datasource.password=dev_password
# Render 클라우드 환경 전용 Fallback 라우팅
mcp.gateway.fallback.routes.sms=https://axhub-tool-sms.onrender.com
mcp.gateway.fallback.routes.email=https://axhub-tool-email.onrender.com
mcp.gateway.fallback.default-url=https://axhub-tool-other.onrender.com
mcp.gateway.fallback.routes.payment=https://axhub-tool-payment.onrender.com
mcp.gateway.fallback.routes.hr=https://axhub-tool-hr.onrender.com
# --- 신한라이프 EAI/MCI 연계 IP 정보 (개발 환경) ---
shinhan.integration.envrTypeCd=D
shinhan.integration.eai.url=http://10.176.32.181
shinhan.integration.internalMci.url=http://10.176.32.173
shinhan.integration.bancaMci.url=http://10.176.32.117
shinhan.integration.externalMci.url=http://10.176.32.176

View File

@@ -0,0 +1,29 @@
# Dev 환경 전용 설정 (개발 서버 DB 연결 정보 등)
# spring:
# datasource:
# url: jdbc:oracle:thin:@//dev-db-host:1521/XEPDB1
# driverClassName: oracle.jdbc.OracleDriver
# username: dev_user
# password: dev_password
# OCI (Oracle Cloud) 개발 환경 라우팅
mcp:
gateway:
fallback:
default-url: http://tool-oth:8084
routes:
sms: http://tool-sms:8082
hr: http://tool-oth:8084
# --- 신한라이프 EAI/MCI 연계 IP 정보 (개발 환경) ---
shinhan:
integration:
envrTypeCd: D
eai:
url: http://10.176.32.181
internalMci:
url: http://10.176.32.173
bancaMci:
url: http://10.176.32.117
externalMci:
url: http://10.176.32.176

View File

@@ -1,27 +0,0 @@
# Local ?섍꼍 ?꾩슜 ?ㅼ젙 (H2 硫붾え由?DB ??
spring.datasource.url=jdbc:p6spy:h2:mem:testdb;DB_CLOSE_DELAY=-1;
spring.datasource.driverClassName=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.username=sa
spring.datasource.password=password
spring.h2.console.enabled=true
# EIMS 동적 라우팅 접속 정보
eims.http.url=http://localhost:${server.port}/api/gateway
eims.tcp.host=127.0.0.1
eims.tcp.port=8090
eims.tcp.timeout=5000
eims.jsp.form.url=http://localhost:${server.port}/mock/jsp-form
eims.jsp.json.url=http://localhost:${server.port}/mock/jsp-json
eims.mci.url=http://localhost:${server.port}/api/mock/esb/api
eims.mcistring.url=http://localhost:${server.port}/api/mock/esb/string
# Gateway/Tool URLs
mcp.adapter.url=http://localhost:${server.port}/rpc/v1/execute
mcp.gateway.url=http://localhost:${server.port}/mcp/api/v1
mcp.tool.host=localhost
# Disable Kafka
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration
# Suppress Kafka Connection Logs
logging.level.org.apache.kafka=ERROR

View File

@@ -0,0 +1,48 @@
# Local 환경 전용 설정 (H2 메모리 DB 등)
spring:
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
autoconfigure:
exclude: org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration
eims:
http:
url: http://localhost:${server.port}/api/gateway
tcp:
host: 127.0.0.1
port: 8090
timeout: 5000
jsp:
form:
url: http://localhost:${server.port}/mock/jsp-form
json:
url: http://localhost:${server.port}/mock/jsp-json
mci:
url: http://localhost:${server.port}/api/mock/esb/api
mcistring:
url: http://localhost:${server.port}/api/mock/esb/string
mcp:
adapter:
url: http://localhost:${server.port}/rpc/v1/execute
gateway:
url: http://localhost:${server.port}/mcp/api/v1
fallback:
default-url: http://localhost:8084
routes:
sms: http://localhost:8082
email: http://localhost:8083
payment: http://localhost:8085
hr: http://localhost:8084
tool:
host: localhost
logging:
level:
org.apache.kafka: ERROR

View File

@@ -1,12 +0,0 @@
# Prod 환경 전용 설정 (운영 서버 DB 연결 정보 등)
# spring.datasource.url=jdbc:oracle:thin:@//prod-db-host:1521/PROD
# spring.datasource.driverClassName=oracle.jdbc.OracleDriver
# spring.datasource.username=prod_user
# spring.datasource.password=prod_password
# --- 신한라이프 EAI/MCI 연계 IP 정보 (운영 환경) ---
shinhan.integration.envrTypeCd=R
shinhan.integration.eai.url=http://10.172.32.181
shinhan.integration.internalMci.url=http://10.172.32.173
shinhan.integration.bancaMci.url=http://10.172.32.117
shinhan.integration.externalMci.url=http://10.172.32.177

View File

@@ -0,0 +1,20 @@
# Prod 환경 전용 설정 (운영 서버 DB 연결 정보 등)
# spring:
# datasource:
# url: jdbc:oracle:thin:@//prod-db-host:1521/PROD
# driverClassName: oracle.jdbc.OracleDriver
# username: prod_user
# password: prod_password
# --- 신한라이프 EAI/MCI 연계 IP 정보 (운영 환경) ---
shinhan:
integration:
envrTypeCd: R
eai:
url: http://10.172.32.181
internalMci:
url: http://10.172.32.173
bancaMci:
url: http://10.172.32.117
externalMci:
url: http://10.172.32.177

View File

@@ -1,52 +0,0 @@
spring.application.name=dap-admin
# Gateway Fallback Routing (For unregistered tools)
mcp.gateway.fallback.routes.sms=http://tool-sms:8082
mcp.gateway.fallback.routes.email=http://tool-email:8083
mcp.gateway.fallback.default-url=http://tool-other:8084
mcp.gateway.fallback.routes.payment=http://tool-payment:8085
mcp.gateway.fallback.routes.hr=http://tool-hr:8086
server.port=8081
server.http2.enabled=true
# 기본적으로 local 환경을 실행
spring.profiles.active=local
# MyBatis 공통 설정
mybatis.mapper-locations=classpath:mapper/**/*.xml
mybatis.type-aliases-package=
mybatis.configuration.map-underscore-to-camel-case=true
spring.sql.init.mode=always
logging.level.com.corundumstudio.socketio=DEBUG
# 우아한 종료 (Graceful Shutdown) 설정
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=20s
# Suppress Kafka Connection Logs
logging.level.org.apache.kafka=ERROR
# Spring AI MCP Server Settings
# spring.ai.mcp.server.protocol=STATELESS
mcp.agent-claims-required=false
mcp.trusted-claims-required=false
mcp.write-approval-required=false
mcp.default-page-size=100
mcp.max-page-size=500
mcp.max-pages-per-call=3
mcp.max-stream-bytes=1048576
mcp.max-response-bytes-from-tool=5242880
mcp.tool-registry-sync-interval-millis=5000
# API 보안 키 설정
mcp.security.tenant-domains.TESTER-DEV=ALL
mcp.security.tenant-domains.system=ALL
# Spring AI OpenAI / Gemini API Config
spring.ai.openai.api-key=AQ.Ab8RN6KFZggsQf8iooY1v_3h3vp2TIjiYB54dV4Yay3vVKEMtg
spring.ai.openai.base-url=https://generativelanguage.googleapis.com/v1beta/openai/
spring.ai.openai.chat.options.model=gemini-flash-latest
spring.ai.openai.chat.options.temperature=0.3

View File

@@ -0,0 +1,56 @@
spring:
application:
name: dap-admin
profiles:
active: local
sql:
init:
mode: always
lifecycle:
timeout-per-shutdown-phase: 20s
ai:
openai:
api-key: AQ.Ab8RN6KFZggsQf8iooY1v_3h3vp2TIjiYB54dV4Yay3vVKEMtg
base-url: https://generativelanguage.googleapis.com/v1beta/openai/
chat:
options:
model: gemini-flash-latest
temperature: 0.3
server:
port: 8081
http2:
enabled: true
shutdown: graceful
mcp:
gateway:
fallback:
default-url: http://tool-oth:8084
routes:
sms: http://tool-sms:8082
hr: http://tool-oth:8084
agent-claims-required: false
trusted-claims-required: false
write-approval-required: false
default-page-size: 100
max-page-size: 500
max-pages-per-call: 3
max-stream-bytes: 1048576
max-response-bytes-from-tool: 5242880
tool-registry-sync-interval-millis: 5000
security:
tenant-domains:
TESTER-DEV: ALL
system: ALL
mybatis:
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: ""
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.corundumstudio.socketio: DEBUG
org.apache.kafka: ERROR

View File

@@ -1,8 +1,8 @@
# SLF4J ??? ?? (logback?? ???) # SLF4J ??? ?? (logback?? ???)
appender=com.p6spy.engine.spy.appender.Slf4JLogger appender=com.p6spy.engine.spy.appender.Slf4JLogger
# ??? ??? ??? ?? (???? ?? ??) # ??? ??? ??? ?? (???? ?? ??)
logMessageFormat=io.shinhanlife.dap.common.config.P6SpySqlFormatter logMessageFormat=io.shinhanlife.dap.lib.config.P6SpySqlFormatter
# ?? ?? 0ms?? (connection ?? ??) ??? # ?? ?? 0ms?? (connection ?? ??) ???
filter.executionThreshold=1 filter.executionThreshold=1

View File

@@ -380,6 +380,7 @@
<a href="/admin/scaffold.html" style="color:#ffffff;" class="font-semibold">Scaffold</a> <a href="/admin/scaffold.html" style="color:#ffffff;" class="font-semibold">Scaffold</a>
<a href="/catalog.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Catalog</a> <a href="/catalog.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Catalog</a>
<a href="/playground.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Playground</a> <a href="/playground.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Playground</a>
<a href="/chat.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Chat</a>
</nav> </nav>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
@@ -462,13 +463,13 @@
<div class="row mb-3"> <div class="row mb-3">
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label">Domain Category</label> <label class="form-label">Domain Category</label>
<input type="text" class="form-control" name="categoryKey" pattern="^[a-z0-9][a-z0-9_-]*$" list="groupList" placeholder="e.g. common, hr, payment" oninput="this.value = this.value.toLowerCase()" required> <input type="text" class="form-control" name="categoryKey" pattern="^[a-z0-9]{3}$" maxlength="3" minlength="3" list="groupList" placeholder="e.g. cmm, smp, pay" oninput="this.value = this.value.toLowerCase()" required>
<datalist id="groupList"> <datalist id="groupList">
<option value="sample">sample</option> <option value="smp">smp</option>
<option value="common">common</option> <option value="cmm">cmm</option>
<option value="customer">customer</option> <option value="cus">cus</option>
<option value="contract">contract</option> <option value="cnt">cnt</option>
<option value="claim">claim</option> <option value="clm">clm</option>
</datalist> </datalist>
</div> </div>
<div class="col-md-6 mt-3 mt-md-0"> <div class="col-md-6 mt-3 mt-md-0">
@@ -477,7 +478,6 @@
<option value="HTTP">HTTP (REST)</option> <option value="HTTP">HTTP (REST)</option>
<option value="TCP">TCP (Socket)</option> <option value="TCP">TCP (Socket)</option>
<option value="MCI">MCI (Legacy)</option> <option value="MCI">MCI (Legacy)</option>
<option value="EAI">EAI (Internal)</option>
</select> </select>
</div> </div>
</div> </div>
@@ -486,10 +486,8 @@
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label">Target Module</label> <label class="form-label">Target Module</label>
<select class="form-select" name="moduleName" id="targetModuleSelect" required> <select class="form-select" name="moduleName" id="targetModuleSelect" required>
<option value="dap-tool-other">dap-tool-other</option> <option value="dap-tool-oth">dap-tool-oth</option>
<option value="dap-tool-email">dap-tool-email</option>
<option value="dap-tool-hr">dap-tool-hr</option> <option value="dap-tool-hr">dap-tool-hr</option>
<option value="dap-tool-payment">dap-tool-payment</option>
<option value="dap-tool-sms">dap-tool-sms</option> <option value="dap-tool-sms">dap-tool-sms</option>
</select> </select>
<div class="input-hint">Destination Pod directory.</div> <div class="input-hint">Destination Pod directory.</div>
@@ -497,12 +495,19 @@
<div class="col-md-6 mt-3 mt-md-0"> <div class="col-md-6 mt-3 mt-md-0">
<label class="form-label">Gateway Registration</label> <label class="form-label">Gateway Registration</label>
<select class="form-select" name="register"> <select class="form-select" name="register">
<option value="true">True (Public)</option> <option value="false" selected>False (Private)</option>
<option value="false">False (Private)</option>
</select> </select>
<div class="input-hint">Controls dynamic routing exposure.</div> <div class="input-hint">Controls dynamic routing exposure.</div>
</div> </div>
</div> </div>
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label">Target System Code (MCI Only)</label>
<input type="text" class="form-control" name="clientSystemCode" pattern="^[a-zA-Z]{4}$" maxlength="4" minlength="4" placeholder="e.g. cfpa" oninput="this.value = this.value.toLowerCase()">
<div class="input-hint">Required for MCI Protocol (4 letters).</div>
</div>
</div>
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-6"> <div class="col-md-6">
@@ -579,7 +584,7 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Category</label> <label class="form-label">Category</label>
<input type="text" class="form-control" id="editCategoryKey" name="categoryKey" pattern="^[a-z0-9][a-z0-9_-]*$" oninput="this.value = this.value.toLowerCase()"> <input type="text" class="form-control" id="editCategoryKey" name="categoryKey" pattern="^[a-z0-9]{3}$" maxlength="3" minlength="3" oninput="this.value = this.value.toLowerCase()">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Description</label> <label class="form-label">Description</label>
@@ -658,7 +663,7 @@
.then(modules => { .then(modules => {
const select = document.getElementById('targetModuleSelect'); const select = document.getElementById('targetModuleSelect');
if (modules && modules.length > 0) { if (modules && modules.length > 0) {
select.innerHTML = modules.map(m => `<option value="${m}" ${m === 'dap-tool-other' ? 'selected' : ''}>${m}</option>`).join(''); select.innerHTML = modules.map(m => `<option value="${m}" ${m === 'dap-tool-oth' ? 'selected' : ''}>${m}</option>`).join('');
} }
}) })
.catch(err => console.error('Failed to load modules:', err)); .catch(err => console.error('Failed to load modules:', err));

View File

@@ -69,6 +69,7 @@
<a href="/admin/scaffold.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Scaffold</a> <a href="/admin/scaffold.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Scaffold</a>
<a href="/catalog.html" style="color:#ffffff;" class="font-semibold">Catalog</a> <a href="/catalog.html" style="color:#ffffff;" class="font-semibold">Catalog</a>
<a href="/playground.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Playground</a> <a href="/playground.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Playground</a>
<a href="/chat.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Chat</a>
</nav> </nav>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
@@ -79,12 +80,24 @@
<main class="max-w-6xl mx-auto px-6 py-10"> <main class="max-w-6xl mx-auto px-6 py-10">
<div class="flex flex-col md:flex-row justify-between items-start md:items-end mb-8"> <div class="flex flex-col md:flex-row justify-between items-start md:items-end mb-8">
<div class="max-w-2xl"> <div class="max-w-2xl w-full">
<h1 class="text-3xl font-bold tracking-tight mb-2" style="color:#f4f4f5;">Registry Catalog</h1> <div class="flex items-center space-x-3 mb-2">
<p class="text-sm" style="color:#a1a1aa;">Currently integrated AI function tools across all modules. View parameters, descriptions, and integration types.</p> <h1 class="text-3xl font-bold tracking-tight" style="color:#f4f4f5;">Registry Catalog</h1>
<button onclick="openGuideModal()" class="w-6 h-6 rounded-full flex items-center justify-center text-sm font-bold bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white transition-colors" title="Connection Guide">?</button>
</div>
<p class="text-sm mb-6" style="color:#a1a1aa;">Currently integrated AI function tools across all modules. View parameters, descriptions, and integration types.</p>
<div class="relative max-w-md w-full">
<input type="text" id="searchInput" placeholder="Search tools by name, description, or category..." class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-4 py-2.5 text-sm text-zinc-200 placeholder-zinc-500 focus:outline-none focus:border-blue-500 transition-colors">
<svg class="w-4 h-4 absolute right-3 top-3 text-zinc-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
</div>
</div> </div>
<div class="mt-4 md:mt-0"> <div class="mt-4 md:mt-0 flex space-x-3 w-full md:w-auto">
<button id="copyMdBtn" class="btn-primary flex items-center"> <button id="copyJsonBtn" class="btn-primary flex items-center justify-center flex-1 md:flex-none" style="background: linear-gradient(135deg, #10b981, #059669); box-shadow: 0 0 20px rgba(16, 185, 129, 0.2);">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
<span id="copyJsonText">Copy Client Config</span>
</button>
<button id="copyMdBtn" class="btn-primary flex items-center justify-center flex-1 md:flex-none">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path></svg> <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path></svg>
<span id="copyBtnText">Copy Markdown Docs</span> <span id="copyBtnText">Copy Markdown Docs</span>
</button> </button>
@@ -99,13 +112,52 @@
</div> </div>
</main> </main>
<!-- Guide Modal -->
<div id="guideModal" class="fixed inset-0 z-[100] hidden flex items-center justify-center">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeGuideModal()"></div>
<div class="relative bg-zinc-900 border border-zinc-700 rounded-xl shadow-2xl w-full max-w-2xl mx-4 overflow-hidden">
<div class="p-5 border-b border-zinc-800 flex justify-between items-center bg-zinc-900/50">
<h3 class="text-lg font-semibold text-zinc-100 flex items-center">
<svg class="w-5 h-5 mr-2 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
AI Agent Connection Guide
</h3>
<button onclick="closeGuideModal()" class="text-zinc-400 hover:text-white transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
<div class="p-6 space-y-6 max-h-[70vh] overflow-y-auto text-sm text-zinc-300">
<div>
<h4 class="font-semibold text-blue-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-blue-500/20 flex items-center justify-center mr-2 text-xs">1</span> Cursor IDE 연동</h4>
<p class="mb-2">1. Cursor 설정 창 열기 (<kbd class="px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 rounded text-xs text-zinc-300">Cmd/Ctrl + ,</kbd>)</p>
<p class="mb-2">2. 사이드바에서 <strong>Features</strong> &gt; <strong>MCP</strong> 메뉴로 이동</p>
<p>3. <strong>+ Add New MCP Server</strong>를 클릭하고, 툴 카테고리의 [Copy SSE URL] 버튼으로 복사한 주소를 `SSE` 타입으로 붙여넣기 하세요.</p>
</div>
<div class="border-t border-zinc-800 pt-6">
<h4 class="font-semibold text-orange-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-orange-500/20 flex items-center justify-center mr-2 text-xs">2</span> Claude Desktop 연동</h4>
<p class="mb-2">1. 아래 설정 파일을 텍스트 에디터로 엽니다:</p>
<div class="bg-black/40 p-3 rounded-lg border border-zinc-800/80 font-mono text-xs mb-3 text-zinc-400">
<div class="mb-1"><strong>Mac:</strong> ~/Library/Application Support/Claude/claude_desktop_config.json</div>
<div><strong>Win:</strong> %APPDATA%\Claude\claude_desktop_config.json</div>
</div>
<p>2. 화면 우측 상단의 <strong>[Copy Client Config]</strong> 버튼을 누른 후, 복사된 JSON 코드를 이 파일 안에 그대로 붙여넣습니다.</p>
</div>
<div class="border-t border-zinc-800 pt-6">
<h4 class="font-semibold text-emerald-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-emerald-500/20 flex items-center justify-center mr-2 text-xs">3</span> 커스텀 Python/Node Agent 연동</h4>
<p class="mb-2">1. MCP 공식 SDK를 설치합니다. <code class="text-xs bg-zinc-800 px-1.5 py-0.5 rounded text-zinc-300 border border-zinc-700">npm i @modelcontextprotocol/sdk</code></p>
<p>2. SSE Client Transport를 사용하여 복사한 카테고리별 URL로 연결합니다.</p>
</div>
</div>
</div>
</div>
<script> <script>
let allTools = []; // 글로벌 변수로 툴 데이터 보관
async function fetchTools() { async function fetchTools() {
try { try {
const response = await fetch('/mcp/api/v1/tools/list'); const response = await fetch('/mcp/api/v1/tools/list');
const data = await response.json(); const data = await response.json();
const tools = data.result?.tools || []; allTools = data.result?.tools || [];
renderCatalog(tools); renderCatalog(allTools);
} catch (err) { } catch (err) {
document.getElementById('catalogContainer').innerHTML = ` document.getElementById('catalogContainer').innerHTML = `
<div style="padding:16px; border:1px solid #7f1d1d; background:rgba(127,29,29,0.15); color:#fca5a5; font-size:14px; border-radius:8px;"> <div style="padding:16px; border:1px solid #7f1d1d; background:rgba(127,29,29,0.15); color:#fca5a5; font-size:14px; border-radius:8px;">
@@ -134,7 +186,12 @@
header.style.cssText = 'margin-bottom:16px; padding-bottom:8px; border-bottom:1px solid #27272a; display:flex; align-items:baseline; justify-content:space-between;'; header.style.cssText = 'margin-bottom:16px; padding-bottom:8px; border-bottom:1px solid #27272a; display:flex; align-items:baseline; justify-content:space-between;';
header.innerHTML = ` header.innerHTML = `
<h2 style="font-size:20px; font-weight:600; color:#f4f4f5; text-transform:capitalize;">${group}</h2> <h2 style="font-size:20px; font-weight:600; color:#f4f4f5; text-transform:capitalize;">${group}</h2>
<span class="geist-mono" style="font-size:12px; color:#71717a;">${grouped[group].length} items</span> <div style="display:flex; align-items:center; gap:8px;">
<span class="geist-mono" style="font-size:12px; color:#71717a;">${grouped[group].length} items</span>
<button onclick="copySseUrl('${group.toLowerCase()}', this)" class="hover:text-blue-400 text-zinc-500 transition-colors p-1.5 rounded hover:bg-zinc-800/50" title="Copy SSE URL">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
</button>
</div>
`; `;
section.appendChild(header); section.appendChild(header);
const grid = document.createElement('div'); const grid = document.createElement('div');
@@ -227,6 +284,60 @@
} }
}); });
document.getElementById('searchInput').addEventListener('input', (e) => {
const query = e.target.value.toLowerCase();
const filtered = allTools.filter(t =>
(t.name && t.name.toLowerCase().includes(query)) ||
(t.displayName && t.displayName.toLowerCase().includes(query)) ||
(t.description && t.description.toLowerCase().includes(query)) ||
(t.categoryKey && t.categoryKey.toLowerCase().includes(query))
);
renderCatalog(filtered);
});
function copySseUrl(category, btnElement) {
const url = `${window.location.origin}/mcp/sse/${category}`;
navigator.clipboard.writeText(url).then(() => {
const originalSvg = btnElement.innerHTML;
btnElement.innerHTML = `<svg class="w-4 h-4 text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>`;
setTimeout(() => { btnElement.innerHTML = originalSvg; }, 2000);
}).catch(() => alert('Failed to copy.'));
}
function openGuideModal() {
document.getElementById('guideModal').classList.remove('hidden');
}
function closeGuideModal() {
document.getElementById('guideModal').classList.add('hidden');
}
document.getElementById('copyJsonBtn').addEventListener('click', () => {
const groups = [...new Set(allTools.map(t => t.categoryKey || 'Others'))];
const config = { mcpServers: {} };
groups.forEach(g => {
const safeKey = g.toLowerCase().replace(/[^a-z0-9]/g, '-');
config.mcpServers[`axhub-${safeKey}`] = {
"command": "node",
"args": [],
"env": {},
"type": "sse",
"url": `${window.location.origin}/mcp/sse/${g.toLowerCase()}`
};
// Note: Claude desktop expects command/args for stdio, but for SSE it usually accepts just url/type or requires specialized settings.
// Adjusted to basic config.
delete config.mcpServers[`axhub-${safeKey}`].command;
delete config.mcpServers[`axhub-${safeKey}`].args;
delete config.mcpServers[`axhub-${safeKey}`].env;
});
const textSpan = document.getElementById('copyJsonText');
const originalText = textSpan.textContent;
navigator.clipboard.writeText(JSON.stringify(config, null, 2)).then(() => {
textSpan.textContent = 'Copied JSON!';
setTimeout(() => { textSpan.textContent = originalText; }, 2000);
}).catch(() => alert('Failed to copy JSON.'));
});
document.addEventListener('DOMContentLoaded', fetchTools); document.addEventListener('DOMContentLoaded', fetchTools);
</script> </script>
</body> </body>

View File

@@ -173,6 +173,10 @@
.replace(/'/g, "&#039;"); .replace(/'/g, "&#039;");
} }
function removeMarkdownEmphasis(text) {
return text.replace(/\*\*/g, '');
}
async function sendMessage() { async function sendMessage() {
const text = chatInput.value.trim(); const text = chatInput.value.trim();
if (!text || isLoading) return; if (!text || isLoading) return;
@@ -205,6 +209,7 @@
// 5. 스트림 읽기 // 5. 스트림 읽기
const reader = response.body.getReader(); const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8"); const decoder = new TextDecoder("utf-8");
let responseText = '';
while (true) { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
@@ -215,7 +220,8 @@
for (const line of lines) { for (const line of lines) {
if (line.startsWith('data:')) { if (line.startsWith('data:')) {
const data = line.substring(5); const data = line.substring(5);
textContainer.innerHTML += escapeHtml(data); responseText += data;
textContainer.textContent = removeMarkdownEmphasis(responseText);
scrollToBottom(); scrollToBottom();
} }
} }

View File

@@ -100,6 +100,7 @@
<a href="/admin/scaffold.html" class="text-zinc-400 hover:text-white transition-colors">Scaffold</a> <a href="/admin/scaffold.html" class="text-zinc-400 hover:text-white transition-colors">Scaffold</a>
<a href="/catalog.html" class="text-zinc-400 hover:text-white transition-colors">Catalog</a> <a href="/catalog.html" class="text-zinc-400 hover:text-white transition-colors">Catalog</a>
<a href="/playground.html" class="text-zinc-400 hover:text-white transition-colors">Playground</a> <a href="/playground.html" class="text-zinc-400 hover:text-white transition-colors">Playground</a>
<a href="/chat.html" class="text-zinc-400 hover:text-white transition-colors">Chat</a>
</nav> </nav>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
@@ -121,7 +122,7 @@
</p> </p>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 w-full max-w-5xl"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full max-w-6xl">
<!-- Scaffold Card --> <!-- Scaffold Card -->
<a href="/admin/scaffold.html" class="card-panel p-8 group block"> <a href="/admin/scaffold.html" class="card-panel p-8 group block">
<div class="w-12 h-12 icon-box rounded-xl flex items-center justify-center mb-6 text-zinc-300"> <div class="w-12 h-12 icon-box rounded-xl flex items-center justify-center mb-6 text-zinc-300">
@@ -163,6 +164,20 @@
Enter Playground <svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg> Enter Playground <svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg>
</div> </div>
</a> </a>
<!-- Chat Card -->
<a href="/chat.html" class="card-panel p-8 group block">
<div class="w-12 h-12 icon-box rounded-xl flex items-center justify-center mb-6 text-zinc-300">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"></path></svg>
</div>
<h2 class="text-lg font-semibold text-zinc-100 mb-3">AI Assistant</h2>
<p class="text-[13px] text-zinc-400 leading-relaxed">
Interact with the MCP tool ecosystem through a natural language interface. Test your LLM routing logic in a premium chat UI.
</p>
<div class="mt-6 flex items-center text-[12px] font-semibold text-zinc-300 group-hover:text-blue-400 group-hover:translate-x-1 transition-all">
Start Chatting <svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg>
</div>
</a>
</div> </div>
</main> </main>
</body> </body>

View File

@@ -111,6 +111,7 @@
<a href="/admin/scaffold.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Scaffold</a> <a href="/admin/scaffold.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Scaffold</a>
<a href="/catalog.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Catalog</a> <a href="/catalog.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Catalog</a>
<a href="/playground.html" style="color:#ffffff;" class="font-semibold">Playground</a> <a href="/playground.html" style="color:#ffffff;" class="font-semibold">Playground</a>
<a href="/chat.html" style="color:#a1a1aa;" class="hover:text-white transition-colors">Chat</a>
</nav> </nav>
</div> </div>
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-3">

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg;
* @package io.shinhanlife.dap.mcg * @package io.shinhanlife.dap.mcg
* @className DapGatewayApplicationTests * @className DapGatewayApplicationTests
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -7,6 +7,7 @@ import java.util.Arrays;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import io.shinhanlife.dap.mcg.sync.DynamicMcpController;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;

View File

@@ -5,7 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema;
import io.shinhanlife.dap.biz.mcp.gateway.dto.ToolMetadata; import io.shinhanlife.dap.mcg.dto.ToolMetadata;
import io.shinhanlife.dap.mcg.sync.RegistryMcpToolSpecificationFactory;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class RegistryMcpToolSpecificationFactoryTest { class RegistryMcpToolSpecificationFactoryTest {

View File

@@ -5,13 +5,13 @@ package io.shinhanlife.dap.mcg.tool.large;
* @package io.shinhanlife.dap.mcg.tool.large * @package io.shinhanlife.dap.mcg.tool.large
* @className PaginationRequestValidatorTest * @className PaginationRequestValidatorTest
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,39 +0,0 @@
package io.shinhanlife.dap.common.integration.mci.component;
import io.shinhanlife.glow.communication.dto.Transfer;
import io.shinhanlife.glow.communication.module.mci.component.GlowMciComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 신한라이프 내부 Glow 표준 컴포넌트 어댑터
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class AxhubMciComponent {
@SuppressWarnings("rawtypes")
private final GlowMciComponent mci;
@SuppressWarnings("unchecked")
public <O, I> Transfer<O> callTo(String itrfName, String rcvSvcId, I inputDto, Class<O> resBodyClass) {
log.info("[AxhubMciComponent] MCI 호출 준비 - 인터페이스: {}, 수신서비스: {}", itrfName, rcvSvcId);
// Header 세팅 로직 생략 (Mock)
Transfer<Object> request = Transfer.builder()
.body(inputDto)
.resBodyClass((Class<Object>) (Class<?>) resBodyClass)
.build();
return syncMci(request);
}
@SuppressWarnings("unchecked")
private <O> Transfer<O> syncMci(Transfer<Object> request) {
log.info("[AxhubMciComponent] GlowMciComponent.sync() 호출");
return (Transfer<O>) mci.sync(request);
}
}

View File

@@ -1,19 +0,0 @@
package io.shinhanlife.dap.common.integration.mci.config;
import io.shinhanlife.glow.communication.module.mci.component.GlowMciComponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* TODO: 실제 Glow Framework 의존성이 추가되어 io.shinhanlife.glow 패키지가
* ComponentScan에 잡히게 되면 이 설정 클래스는 삭제하세요.
*/
@Configuration
public class GlowMockConfig {
@Bean
@SuppressWarnings("rawtypes")
public GlowMciComponent glowMciComponent() {
return new GlowMciComponent();
}
}

View File

@@ -1,481 +0,0 @@
package io.shinhanlife.dap.common.util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
/**
* MCP Tool 코드를 자동 생성(Scaffolding)하는 유틸리티 클래스
*
* [실행 방법]
* 방법 1. IDE(IntelliJ 등)에서 직접 실행 (대화형 모드 추천 ⭐)
* - 이 클래스(ToolScaffolder.java)를 열고 main 메서드를 직접 실행(Run)합니다.
* - 콘솔 창에 뜨는 질문에 차례대로 값을 입력하기만 하면 파일이 생성됩니다.
*
* 방법 2. 커맨드라인(터미널)에서 실행 (명령어 기반)
* - 컴파일: javac -encoding UTF-8 dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/util/ToolScaffolder.java
* - 실행: java -cp dap-tool-core/src/main/java io.shinhanlife.dap.mcc.util.ToolScaffolder [이름] [ID] "[설명]" "[그룹]" "[통신방식]" "[모듈명]"
*/
/**
* @package io.shinhanlife.dap.mcc.util
* @className ToolScaffolder
* @description AX HUB 시스템 처리 클래스
* @author 김형식
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성
*
* </pre>
*/
public class ToolScaffolder {
private static final String BASE_PACKAGE = "io.shinhanlife.dap.mcc";
private static final String BASE_PACKAGE_PATH = "src/main/java/io/shinhanlife/dap/mcc";
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("=========================================");
System.out.println(" MCP Tool Scaffolder (Java CLI) ");
System.out.println("=========================================\n");
String baseName = getOrAsk(args, 0, scanner, "1. 생성할 Tool의 기본 이름 (예: ExchangeRate) [영문 PascalCase]: ");
String interfaceId = getOrAsk(args, 1, scanner, "2. 레거시 API 인터페이스 ID (예: EXCH_001): ");
String description = getOrAsk(args, 2, scanner, "3. Tool 기능 설명 (예: 환율 조회): ");
String group = getOrAsk(args, 3, scanner, "4. Tool 소속 그룹 (예: SAMPLE, NOTIFICATION, CLAIM, POLICY, HR, CONTRACT, CUSTOMER 등): ");
if (group.isEmpty()) group = "COMMON";
String routingType = getOrAsk(args, 4, scanner, "5. 통신 프로토콜 (예: HTTP, TCP, MCI, EAI): ");
if (routingType.trim().isEmpty()) {
routingType = "HTTP";
}
String moduleName = getOrAsk(args, 5, scanner, "6. 코드를 생성할 모듈 (기본: dap-tool-other): ");
if (moduleName.trim().isEmpty()) {
moduleName = "dap-tool-other";
}
String defaultAuthor = System.getProperty("user.name");
String defaultDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
String author = getOrAsk(args, 6, scanner, "7. 작성자 (엔터 입력 시 '" + defaultAuthor + "'): ");
if (author.trim().isEmpty()) author = defaultAuthor;
String createDate = getOrAsk(args, 7, scanner, "8. 작성일 (엔터 입력 시 '" + defaultDate + "'): ");
if (createDate.trim().isEmpty()) createDate = defaultDate;
String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate, true);
System.out.println(result);
}
private static String getOrAsk(String[] args, int index, Scanner scanner, String prompt) {
if (args.length > index) {
return args[index];
}
System.out.print(prompt);
return scanner.nextLine().trim();
}
public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate, boolean register) throws IOException {
baseName = toPascalCase(baseName);
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
Path serviceDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "service"));
Path dtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "dto"));
Path legacyDtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "legacy"));
Path converterDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "converter"));
Files.createDirectories(serviceDir);
Files.createDirectories(dtoDir);
Files.createDirectories(legacyDtoDir);
Files.createDirectories(converterDir);
StringBuilder log = new StringBuilder();
// Generate Req DTO
String reqContent = """
package %s.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import %s.annotation.McpParameter;
import lombok.Data;
/**
* @package %s.dto
* @className %sReq
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class %sReq {
@McpParameter(description = "수신자 전화번호", required = true)
private String phoneNumber;
@McpParameter(description = "전송할 메시지 내용", required = true)
private String message;
}
""".formatted(BASE_PACKAGE, BASE_PACKAGE, BASE_PACKAGE, baseName, author, createDate, createDate, author, baseName);
Files.writeString(dtoDir.resolve(baseName + "Req.java"), reqContent);
// Generate Res DTO
String resContent = """
package %s.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
/**
* @package %s.dto
* @className %sRes
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class %sRes {
private String status;
private String message;
// TODO: Add response fields here
}
""".formatted(BASE_PACKAGE, BASE_PACKAGE, baseName, author, createDate, createDate, author, baseName);
Files.writeString(dtoDir.resolve(baseName + "Res.java"), resContent);
String toolName = baseName.isEmpty() ? baseName : Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1);
boolean isMci = "MCI".equalsIgnoreCase(routingType);
String serviceContent;
if (isMci) {
serviceContent = """
package %s.service;
import %s.annotation.McpFunction;
import %s.annotation.McpTool;
import %s.dto.%sReq;
import %s.dto.%sRes;
import io.shinhanlife.dap.common.integration.mci.component.AxhubMciComponent;
import io.shinhanlife.glow.communication.dto.Transfer;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import org.mapstruct.factory.Mappers;
import %s.converter.%sLegacyConverter;
import %s.legacy.%sLegacyReq;
/**
* @package %s.service
* @className %sService
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Slf4j
@Service
@RequiredArgsConstructor
@McpTool(
routingType = "%s",
categoryKey = "%s"
)
public class %sService {
private final AxhubMciComponent mci;
private final %sLegacyConverter converter = Mappers.getMapper(%sLegacyConverter.class);
@McpFunction(
displayName = "%s 툴",
name = "%s",
description = "%s",
prompt = "%s",
mappingId = "%s",
register = %s,
requiresApproval = false,
openWorldHint = true
)
public Object execute(%sReq req) {
log.info("[MCI Tool] {} 요청 수신.", "%s");
try {
// MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO)
%sLegacyReq legacyReq = converter.toLegacyReq(req);
Transfer<Object> resTransfer = mci.callTo(
"%s",
null,
legacyReq,
Object.class
);
return resTransfer.getBody() != null ? resTransfer.getBody() : Map.of("status", "SUCCESS");
} catch (Exception e) {
log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e);
return Map.of("status", "ERROR", "message", e.getMessage() != null ? e.getMessage() : "Unknown error");
}
}
}
""".formatted(
BASE_PACKAGE,
BASE_PACKAGE,
BASE_PACKAGE,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
author,
createDate,
createDate, author,
routingType, group.toLowerCase(),
baseName,
baseName, baseName,
baseName, toolName, description, description + " 해줘.", interfaceId, register,
baseName,
baseName,
baseName,
interfaceId
);
} else {
serviceContent = """
package %s.service;
import %s.annotation.McpFunction;
import %s.annotation.McpTool;
import %s.dto.%sReq;
import %s.dto.%sRes;
import %s.converter.%sLegacyConverter;
import org.springframework.stereotype.Service;
import org.mapstruct.factory.Mappers;
/**
* @package %s.service
* @className %sService
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Service
@McpTool(
routingType = "%s",
categoryKey = "%s"
)
public class %sService extends AbstractMcpToolService {
private final %sLegacyConverter converter = Mappers.getMapper(%sLegacyConverter.class);
@McpFunction(
displayName = "%s 툴",
name = "%s",
description = "%s",
prompt = "%s",
mappingId = "%s",
register = %s,
requiresApproval = false
)
public Object execute(%sReq req) {
// %sLegacyReq legacyReq = converter.toLegacyReq(req);
return executeLegacy("%s", "%s", req); // Or pass legacyReq
}
}
""".formatted(
BASE_PACKAGE,
BASE_PACKAGE,
BASE_PACKAGE,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
author,
createDate,
createDate, author,
routingType, group.toLowerCase(),
baseName,
baseName, baseName,
baseName, toolName, description, description + " 해줘.", interfaceId, register,
baseName,
baseName,
routingType, interfaceId
);
}
Files.writeString(serviceDir.resolve(baseName + "Service.java"), serviceContent);
String legacyReqContent = """
package %s.legacy;
import lombok.Data;
/**
* @package %s.legacy
* @className %sLegacyReq
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Data
public class %sLegacyReq {
/**
* EAI 시스템이 요구하는 수신자 번호 파라미터명
*/
private String phone;
/**
* EAI 시스템이 요구하는 메시지 내용 파라미터명
*/
private String content;
}
""".formatted(BASE_PACKAGE, BASE_PACKAGE, baseName, author, createDate, createDate, author, baseName);
Files.writeString(legacyDtoDir.resolve(baseName + "LegacyReq.java"), legacyReqContent);
String legacyResContent = """
package %s.legacy;
import lombok.Data;
/**
* @package %s.legacy
* @className %sLegacyRes
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Data
public class %sLegacyRes {
// TODO: Add legacy response fields here
}
""".formatted(BASE_PACKAGE, BASE_PACKAGE, baseName, author, createDate, createDate, author, baseName);
Files.writeString(legacyDtoDir.resolve(baseName + "LegacyRes.java"), legacyResContent);
String converterContent = """
package %s.converter;
import %s.dto.%sReq;
import %s.dto.%sRes;
import %s.legacy.%sLegacyReq;
import %s.legacy.%sLegacyRes;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
* @package %s.converter
* @className %sLegacyConverter
* @description AX HUB 시스템 처리 클래스
* @author %s
* @create %s
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* %s %s 최초생성
*
* </pre>
*/
@Mapper(componentModel = "spring")
public interface %sLegacyConverter {
@Mapping(source = "phoneNumber", target = "phone")
@Mapping(source = "message", target = "content")
%sLegacyReq toLegacyReq(%sReq req);
@Mapping(source = "phone", target = "phoneNumber")
@Mapping(source = "content", target = "message")
%sReq toReq(%sLegacyReq legacyReq);
// %sRes toRes(%sLegacyRes legacyRes);
}
""".formatted(
BASE_PACKAGE,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName,
BASE_PACKAGE, baseName, author, createDate, createDate, author,
baseName, baseName, baseName, baseName, baseName, baseName, baseName
);
Files.writeString(converterDir.resolve(baseName + "LegacyConverter.java"), converterContent);
log.append("\n=========================================\n");
log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n");
log.append("=========================================\n");
log.append("[Service] ").append(serviceDir.resolve(baseName + "Service.java")).append("\n");
log.append("[Req DTO] ").append(dtoDir.resolve(baseName + "Req.java")).append("\n");
log.append("[Res DTO] ").append(dtoDir.resolve(baseName + "Res.java")).append("\n");
log.append("[Legacy Req DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyReq.java")).append("\n");
log.append("[Legacy Res DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyRes.java")).append("\n");
log.append("[Legacy Converter] ").append(converterDir.resolve(baseName + "LegacyConverter.java")).append("\n");
log.append("\n Tip: ").append(interfaceId).append(" 목업 데이터를 mock-responses.json에 추가하세요.\n");
return log.toString();
}
private static String toPascalCase(String str) {
if (str == null || str.isEmpty()) {
return str;
}
StringBuilder result = new StringBuilder();
boolean capitalizeNext = true;
for (char c : str.toCharArray()) {
if (c == '_' || c == '-' || c == ' ') {
capitalizeNext = true;
} else if (capitalizeNext) {
result.append(Character.toUpperCase(c));
capitalizeNext = false;
} else {
result.append(c);
}
}
if (result.length() > 0) {
result.setCharAt(0, Character.toUpperCase(result.charAt(0)));
}
return result.toString();
}
}

View File

@@ -1,4 +1,4 @@
package io.shinhanlife.dap.common.adapter.aop; package io.shinhanlife.dap.lib.adapter.aop;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
@@ -9,16 +9,16 @@ import org.springframework.stereotype.Component;
import java.util.Arrays; import java.util.Arrays;
/** /**
* @package io.shinhanlife.dap.common.adapter.aop * @package io.shinhanlife.dap.lib.adapter.aop
* @className EimsMonitoringAspect * @className EimsMonitoringAspect
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */
@@ -27,8 +27,8 @@ import java.util.Arrays;
@Component @Component
public class EimsMonitoringAspect { public class EimsMonitoringAspect {
// 포인트컷: io.shinhanlife.dap.common.adapter.sender 패키지 내의 EimsSender를 구현한 모든 클래스의 메서드를 타겟으로 지정합니다. // 포인트컷: io.shinhanlife.dap.lib.adapter.sender 패키지 내의 EimsSender를 구현한 모든 클래스의 메서드를 타겟으로 지정합니다.
@Around("execution(* io.shinhanlife.dap.common.adapter.sender.*EimsSender.*(..))") @Around("execution(* io.shinhanlife.dap.lib.adapter.sender.*EimsSender.*(..))")
public Object monitorEimsCommunication(ProceedingJoinPoint joinPoint) throws Throwable { public Object monitorEimsCommunication(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 호출되는 클래스와 메서드 이름 추출 // 1. 호출되는 클래스와 메서드 이름 추출

View File

@@ -1,7 +1,7 @@
package io.shinhanlife.dap.common.adapter.connector; package io.shinhanlife.dap.lib.adapter.connector;
import io.shinhanlife.dap.common.adapter.support.DynamicPayloadBuilder; import io.shinhanlife.dap.lib.adapter.support.DynamicPayloadBuilder;
import io.shinhanlife.dap.common.adapter.support.DynamicSchemaValidator; import io.shinhanlife.dap.lib.adapter.support.DynamicSchemaValidator;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter; import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -12,16 +12,16 @@ import java.util.Map;
import java.util.List; import java.util.List;
/** /**
* @package io.shinhanlife.dap.common.adapter.connector * @package io.shinhanlife.dap.lib.adapter.connector
* @className ExternalApiConnector * @className ExternalApiConnector
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,7 +1,7 @@
package io.shinhanlife.dap.common.adapter.connector; package io.shinhanlife.dap.lib.adapter.connector;
import io.shinhanlife.dap.common.adapter.support.DynamicPayloadBuilder; import io.shinhanlife.dap.lib.adapter.support.DynamicPayloadBuilder;
import io.shinhanlife.dap.common.adapter.support.DynamicSchemaValidator; import io.shinhanlife.dap.lib.adapter.support.DynamicSchemaValidator;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter; import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -12,16 +12,16 @@ import java.util.Map;
import java.util.List; import java.util.List;
/** /**
* @package io.shinhanlife.dap.common.adapter.connector * @package io.shinhanlife.dap.lib.adapter.connector
* @className InternalSystemConnector * @className InternalSystemConnector
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,6 +1,6 @@
package io.shinhanlife.dap.common.adapter.connector; package io.shinhanlife.dap.lib.adapter.connector;
import io.shinhanlife.dap.common.adapter.support.ResultStandardizer; import io.shinhanlife.dap.lib.adapter.support.ResultStandardizer;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter; import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -13,16 +13,16 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* @package io.shinhanlife.dap.common.adapter.connector * @package io.shinhanlife.dap.lib.adapter.connector
* @className LegacyDbConnector * @className LegacyDbConnector
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,7 +1,7 @@
package io.shinhanlife.dap.common.adapter.connector; package io.shinhanlife.dap.lib.adapter.connector;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.common.adapter.sender.EimsSender; import io.shinhanlife.dap.lib.adapter.sender.EimsSender;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.RequestNotPermitted; import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter; import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
@@ -12,19 +12,19 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.shinhanlife.dap.common.adapter.util.LegacyDataTransformer; import io.shinhanlife.dap.lib.adapter.util.LegacyDataTransformer;
/** /**
* @package io.shinhanlife.dap.common.adapter.connector * @package io.shinhanlife.dap.lib.adapter.connector
* @className LegacyEimsConnector * @className LegacyEimsConnector
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,4 +1,4 @@
package io.shinhanlife.dap.common.adapter.connector; package io.shinhanlife.dap.lib.adapter.connector;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -8,16 +8,16 @@ import org.springframework.stereotype.Service;
import java.util.Map; import java.util.Map;
/** /**
* @package io.shinhanlife.dap.common.adapter.connector * @package io.shinhanlife.dap.lib.adapter.connector
* @className ThirdPartySecurityConnector * @className ThirdPartySecurityConnector
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,4 +1,4 @@
package io.shinhanlife.dap.common.adapter.dto; package io.shinhanlife.dap.lib.adapter.dto;
import lombok.Builder; import lombok.Builder;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -8,16 +8,16 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* @package io.shinhanlife.dap.common.adapter.dto * @package io.shinhanlife.dap.lib.adapter.dto
* @className ErrorDetail * @className ErrorDetail
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,19 +1,19 @@
package io.shinhanlife.dap.common.adapter.dto; package io.shinhanlife.dap.lib.adapter.dto;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* @package io.shinhanlife.dap.common.adapter.dto * @package io.shinhanlife.dap.lib.adapter.dto
* @className JsonRpcRequest * @className JsonRpcRequest
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

View File

@@ -1,4 +1,4 @@
package io.shinhanlife.dap.common.adapter.dto; package io.shinhanlife.dap.lib.adapter.dto;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Getter; import lombok.Getter;
@@ -6,16 +6,16 @@ import lombok.Setter;
// 2. 응답 DTO // 2. 응답 DTO
/** /**
* @package io.shinhanlife.dap.common.adapter.dto * @package io.shinhanlife.dap.lib.adapter.dto
* @className JsonRpcResponse * @className JsonRpcResponse
* @description AX HUB 시스템 처리 클래스 * @description AX HUB 시스템 처리 클래스
* @author 김형식 * @author 0986406
* @create 2026.09.01 * @create 2026.09.01
* <pre> * <pre>
* ---------- 개정이력 ---------- * ---------- 개정이력 ----------
* 수정일 수정자 수정내용 * 수정일 수정자 수정내용
* ---------- -------- --------------------------- * ---------- -------- ---------------------------
* 2026.09.01 김형식 최초생성 * 2026.09.01 0986406 최초생성
* *
* </pre> * </pre>
*/ */

Some files were not shown because too many files have changed in this diff Show More