# 아키텍처와 입력 계약 ## 책임 경계 | 구성요소 | 책임 | DB 접근 | |---|---|---| | `search_carrier_performance` | 기존 `HMM_CARRIER_FEDERATION_SEARCH`를 통한 Bearer/VPD 기반 Select AI Federation 조회 | 허용 | | AI 웹 콘솔 | 도구 계약을 판별해 조회 결과를 정규화하고 렌더러를 후속 호출 | 없음 | | `render_hmm_carrier_report` | DB CLOB 템플릿에 허용된 JSON을 매핑 | 템플릿만 읽음 | | 브라우저 | 반환 HTML 표시·다운로드 | 없음 | ```text HMM portal ──► /mcp (Bearer) ──► Backoffice MCP facade ──► DB Agent Tool │ VPD applied rows │ Console │ report MCP tool call │ HMM_REPORT_TEMPLATES │ HTML 응답 ``` 리포트 MCP도 같은 Bearer 인증을 통과해야 하지만, 권한 판단은 조회 MCP에서 끝난다. 리포트 입력의 임의 사용자 ID를 신뢰하거나 DB를 재조회하지 않는다. ## 포털의 범용 순차 호출 규칙 포털은 `render_hmm_carrier_report`라는 이름을 조건문에 넣지 않는다. 발견한 MCP 도구가 아래 계약을 동시에 보이면 **이전 결과 입력형 렌더러**로 분류한다. - 입력 스키마에 `reportJson`·`report_payload`처럼 리포트 JSON/payload를 받는 문자열이 있다. - 설명에 HTML/리포트/렌더링 의도와 `조회 결과`, `후속 처리`, `already-authorized`처럼 선행 결과를 사용한다는 의도가 있다. 사용자가 리포트·보고서·대시보드·차트·HTML을 요청하고 이 렌더러가 발견되면, 기존 LLM 라우터는 렌더러를 제외한 데이터 도구 중 하나를 먼저 선택한다. 첫 응답의 `items`, `results`, `rows` 또는 `response.result` 안의 JSON 배열 문자열을 같은 방식으로 구조화하고, camelCase JSON으로 정규화해 두 번째 도구에 전달한다. 포털은 렌더러의 `html` 응답을 iframe으로 표시한다. 이 규칙은 특정 Tool 이름, 사용자 코드나 예상 행 수를 조건으로 사용하지 않는다. ## 변경 금지 경계 - `search_carrier_performance`의 DB target은 기존 `HMM_CARRIER_FEDERATION_SEARCH`다. - 별도 호환성 시험 서버 `hmm-mcp.cloud-handson.com`은 이 운영 경로를 대신하지 않는다. - HTML 추가를 이유로 조회 Agent Tool, Select AI profile, VPD 정책 또는 조회 package를 생성·교체하지 않는다. - renderer는 선행 결과만 표현하며 누락 행을 조회하거나 고정 샘플로 채우지 않는다. ## `reportJson` 계약 최상위에는 `report` 객체와 `rows` 배열만 허용한다. `report`에는 `id`, `category`, `title`, `generatedAt`, `requestedBy`, `question`, `answer`, `execution`, `evidence`, `limitation`을 넣는다. 행에는 담당자·선사 식별자와 최신 KPI만 넣는다. `report.title`은 사용자 질문 원문이 아니다. 포털이 모델에 다음 제목 계약을 지시해 만든 짧은 업무 제목이다. - `HTML로 보여줘`, `리포트로 만들어줘`와 같은 출력 형식·행동 문구는 제거한다. - 사용자·팀·업무 대상처럼 범위를 구분하는 식별자는 유지한다. - 문장형 답변이 아니라 화면 머리글에 맞는 명사형 제목으로 만든다. - 템플릿이 붙이는 고정 부제와 같은 문구를 반복하지 않는다. 제목 생성이 실패하면 전체 질문을 제목으로 사용하지 않고 짧은 일반 업무 제목으로 안전하게 대체한다. 이 규칙은 특정 사용자 코드나 조회 행 수를 조건으로 사용하지 않는다. ## 포털 표시 계약 renderer 응답에 유효한 `html` 또는 `rendered_html`이 있으면 HTML artifact가 최종 표현물이다. 포털의 일반 답변 생성 지침은 HTML 태그, Markdown 표, 업무 행 전체를 다시 만들지 않고 제목과 조회 건수, 아래 리포트 확인 안내만 반환한다. 포털은 같은 조건을 출력 후에도 검사해 모델이 HTML을 반환하더라도 안전한 짧은 안내문으로 정규화한다. ## 조회 질문과 표현 요청 분리 사용자의 한 문장에는 데이터 요구와 표현 요구가 함께 있을 수 있다. 포털은 Agent instruction으로 두 의도를 분리한다. ```text 원문: E1001 팀 선사 KPI를 HTML로 보여줘 조회 단계: E1001 팀 선사 KPI를 보여줘 표현 단계: 조회된 구조화 행을 HTML 리포트로 렌더링 ``` 조회 단계 재작성은 직원·팀·기간·지표·필터를 모두 유지하고 `HTML`, `리포트`, `차트`, `대시보드` 같은 출력 형식과 생성 행동만 제거한다. 원문은 `report.question`에 보존한다. Select AI가 만든 `htmlRow`, HTML 태그 또는 Markdown 표는 구조화 업무 행으로 간주하지 않으며 renderer 입력으로 전달하지 않는다. 서버는 JSON 크기, 행 수, 문자열 길이, 숫자 형식을 제한하고, 템플릿에 주입할 JSON에서 ``를 이스케이프한다. payload는 저장하지 않는다. ## 배포 도구 계약 `BACKOFFICE_MCP_TOOLS`에 다음과 같이 등록한다. 실제 환경 변수에는 비밀값을 넣지 않는다. ```json { "name": "render_hmm_carrier_report", "label": "HMM 선사 실적 HTML 리포트", "description": "VPD 적용 선사 실적 조회 결과를 HMM HTML 리포트로 표현합니다.", "argumentName": "reportJson", "argumentDescription": "정규화된 선사 실적 리포트 JSON입니다.", "executionType": "AGENT_TOOL", "targetName": "HMM_CARRIER_REPORT_RENDERER", "targetParameterName": "P_REPORT_JSON" } ``` `targetName`은 DBMS_CLOUD_AI_AGENT custom tool `HMM_CARRIER_REPORT_RENDERER`다. 템플릿에는 `const reportData = __REPORT_DATA__;` 자리만 둔다. DB 함수는 호출 시 전달받은 JSON을 이 자리에 삽입하고, 조회 Tool을 호출하거나 기본 업무 행을 보충하지 않는다.