Skip to content

ProcessCenter 탐색 어댑터 계약 (ExploreGateway 연동) ​

상태: 확정 · 구현: server/remoteExplore.ts (POST /api/explore/v1/search) · 테스트: server/remoteExplore.test.ts상대 서비스: ExploreGateway — 포털 탐색 조합 오케스트레이터(ExploreGateway/docs/SERVICE_BOUNDARIES.md, docs/control-plane-contract.md)

1. 방향 (2026-09-13 정정) ​

초기 작성된 위임 계획(ProcessCenter → 게이트웨이 호출)은 방향이 반대여서 폐기했다. 실제 구조는 다음과 같다.

Portal Control Center  ──(control plane catalog·사용자 Scope)──▶  ExploreGateway
                                                                     │
                                          포털 explore.endpoint 호출 │  (service_token)
                                                                     ▼
                                                       ProcessCenter 어댑터
                                                       POST /api/explore/v1/search
  • ExploreGateway: catalog와 Scope의 교집합으로 어댑터를 선택·실행하고 결과를 정규화한다(부분 실패·timeout·catalogStale 포함).
  • ProcessCenter: 자신의 업무 데이터 검색 API를 어댑터로 제공하고 원본 접근정책을 최종 적용한다.
  • 문서 인덱스·RAG·citation은 RAGCenter가 소유한다(ExploreGateway/ProcessCenter가 소유하지 않는다).

2. 엔드포인트 ​

메서드경로설명
POST/api/explore/v1/searchProcessCenter 업무 데이터(프로세스 노드) 검색

Catalog 등록 값(예):

json
{ "portalId": "process-center", "capabilities": ["search"], "explore": { "endpoint": "/api/explore/v1/search", "timeoutMs": 1500, "authMode": "service_token" } }

3. 인증·컨텍스트 ​

항목규칙
인증Authorization: Bearer <EXPLORE_GATEWAY_API_KEY> — 상수 시간 비교, 미설정·불일치 시 401 explore_gateway_auth_required
사용자 컨텍스트x-explore-subject-id 필수(없으면 400 explore_subject_required) — 게이트웨이가 인증한 사용자 식별자
상관관계x-explore-request-id(선택) — 없으면 서버가 생성하며 응답 meta.requestId로 에코
권한각 어댑터가 자신의 원본 접근정책을 최종 적용한다(게이트웨이는 대체하지 않음)

4. 요청·응답 ​

요청

jsonc
{ "query": "휴가 신청", "limit": 20 }
  • query: 1~200자(공백 제거 후), 위반 시 400 invalid_explore_query
  • limit: 1~30 정수(기본 20, 범위 밖은 잘라서 적용)

응답 200

jsonc
{
  "results": [
    { "id": "process:19", "kind": "record", "portalId": "process-center", "portalLabel": "Process Center",
      "title": "운영 관리", "summary": "…", "meta": "L6 · L6-000001", "href": "/processes?node=19" }
  ],
  "meta": { "requestId": "…", "subjectId": "a-user" }
}

오류

HTTPerror의미
400explore_subject_requiredx-explore-subject-id 누락
400invalid_explore_queryquery 길이 위반
401explore_gateway_auth_required서비스 토큰 미설정·불일치
500(express 기본 오류 처리)서버 내부 오류 — 게이트웨이는 해당 포털을 unavailablePortals로 기록

5. 관련 문서 ​

  • 기계 판독 계약: docs/explore-adapter.openapi.json
  • ExploreGateway 경계·control plane 계약: ExploreGateway/docs/SERVICE_BOUNDARIES.md, docs/control-plane-contract.md
  • 어댑터 온보딩·런타임 준비 상태: ExploreGateway/docs/adapter-onboarding.md (카탈로그 등록 PORTAL_EXPLORE_CATALOG_JSON, 키 주입, 게이트웨이 런타임 미구현 항목)
  • RAG 경계(RAGCenter 소유): UiCenter/docs/SERVICE_BOUNDARIES.md, FileStore/docs/ARCHITECTURE.md

6. 개발 스택 연동 (검증 완료, 2026-09-13) ​

항목값
PC 어댑터 토큰EXPLORE_GATEWAY_API_KEY=local-dev-explore-gateway-key(게이트웨이 PORTAL_SERVICE_TOKENS_JSON과 동일 값)
게이트웨이 → PC 접근포털 baseUrl이 http://localhost:3000이므로 게이트웨이 컨테이너에서 loopback 전달자 사용
게이트웨이 → PortalConsole catalogCONTROL_PLANE_ORIGIN=http://portal-console:3000 + directory:read 포털 API key
DS 카탈로그 정책PORTAL_EXPLORE_CATALOG_JSON={"process-center":{"capabilities":["search"],"endpoint":"/api/explore/v1/search","timeoutMs":1500}}
e2e 결과게이트웨이(3500) 호출 → ProcessCenter 업무 데이터 1건 반환(partial=false, catalogStale=false)

7. 탐색 UI 연동 준비 상태 (2026-09-13) ​

공통 UI는 준비 완료 — portal-foundation 0.6.155의 PortalExploreSearch + @hohyun94/portal-operations 0.3.0의 createExploreGatewayClient(PC vendor 반영 완료: hohyun94-portal-foundation-0.6.155.tgz·hohyun94-portal-operations-0.3.0.tgz).

ts
const client = createExploreGatewayClient({ baseUrl: EXPLORE_GATEWAY_URL, getAccessToken: () => <사용자 토큰> });
<PortalExploreSearch onSearch={query => client.search({ query, limit: 20 })} />

남은 게이트: 사용자 토큰 전달 방식 ⚠️

  • 게이트웨이는 DirectoryService 사용자 토큰(JWT) 만 인증 수단으로 받는다(aud=directory-user).
  • ProcessCenter는 로그인 시 DS 흐름에서 accessToken을 받지만 자체 서명 세션 쿠키만 보관하고 DS 토큰을 보관하지 않는다(브라우저도 HttpOnly라 읽을 수 없다).
  • 따라서 다음 중 하나를 결정해야 한다.
    1. 서버 프록시 + 위임 토큰(권장) — ✅ 구현·검증 완료: DS가 POST /api/internal/delegation-token(경로 B)을 제공하고, 개발 스택에서 위임 토큰으로 게이트웨이 탐색이 성공하는 것을 확인했다(DirectoryService/docs/delegation-token-contract.md). PC에는 서버 프록시 절차만 추가하면 된다.
    2. DS 토큰 보관 — 로그인 시 받은 사용자 토큰을 사용자별로 안전하게 보관하고 만료 시 재발급(보안·운영 부담).
    3. (임시) 개발 스택에서만 서버가 단기 토큰을 발급해 검증 — 운영 사용 금지.

결정·구현 현황(2026-09-13): 1안 채택 · DS 측 D1(서비스 토큰 일반화)·D3(위임 발급, 경로 B)·D2(테넌트/등급 기본값) 구현 완료. PC 측 서버 프록시와 화면 연결도 완료했다(아래).

PC 구현(2026-09-13) ✔

구성위치내용
위임 토큰 클라이언트server/directoryDelegation.tsissueDelegationToken({ subject, audience, scope }) — DS /api/internal/delegation-token 호출, 만료 30초 전까지 캐시
통합 탐색 서비스server/exploreGatewaySearch.tssearchAcrossPortals() — openId(directory:<id>) → subject 변환 → 위임 토큰 → PF createExploreGatewayClient로 게이트웨이 호출, 미설정 시 configured:false
보호된 절차server/routers/explore.tsexplore.gatewaySearch(query — 상단 검색창이 입력 중 호출) — 401→UNAUTHORIZED, 그 외→BAD_GATEWAY
화면client/src/pages/Home.tsx(상단 검색창) + App.tsx별도 /explore 화면은 없앴다 — 옛 주소는 /processes 로 되돌리고, 연합 결과는 상단 검색창이 href 로 연다
환경composePC: EXPLORE_GATEWAY_URL·EXPLORE_GATEWAY_AUDIENCE=explore-gateway / 게이트웨이: PORTAL_CONSOLE_JWT_AUDIENCE=explore-gateway

검증: 단위 테스트 5건(발급·캐시·오류·미설정·subject 변환) + 개발 스택 전체 체인 — 위임 토큰(aud=explore-gateway) 발급 → 게이트웨이 탐색 성공(업무 데이터 반환) · 게이트웨이 헬스 adapters:["process-center"] · PC 200.

참고: PC의 사용자 openId는 directory:<directoryUserId> 형식이므로, 위임 요청의 subject는 접두어를 제거한 값이다.

§14 통합 답변(answer) — 정본은 중앙 RAG 하나다 (2026-10-05) ​

항목상태
explore.gatewayAsk(셸 상단 검색의 질문 경로)게이트웨이 위임 단일 경로(server/exploreGatewaySearch.ts → 공용 createExploreGateway)
로컬 RAG 폴백제거 — 게이트웨이 장애·무응답은 빈 답(화면은 검색 결과만) 또는 BAD_GATEWAY 오류로 드러난다. 같은 질문에 두 답이 생기지 않게 한다
DISABLE_LOCAL_RAG_FALLBACK env제거(폴백이 없어져 스위치가 필요 없다)
explore.answer 절차(로컬 RAG 직접 호출)제거
PC의 answer provider(POST /api/explore/v1/ask)제거 — 카탈로그에서도 process-center 의 answer 능력을 내린다(게이트웨이는 응답 없음으로 처리하고 다음 provider 를 쓴다)
PC 자체 RAG 기능(trpc.rag.*·/rag 화면)유지 — 사내 문서 전용 화면이며 통합 탐색 경로와 분리한다

근거: 게이트웨이는 후보 provider 를 순서대로 시도해 첫 답에서 멈춘다. provider 가 둘이면 질문마다 답이 달라질 수 있어 사용자가 어느 답을 믿을지 판단할 수 없다 — 정본을 중앙 RAG(RagService) 하나로 둔다(ExploreGateway/docs/adapter-onboarding.md §3-2).

선행 조건: PC 문서가 RagService 색인에 있어야 한다(위임 scope rag:read·rag:sync·rag:admin + server/rag/ragIdentity.ts 의 uuid5 식별자로 발행). 적재가 끝나기 전 배포라면 PC 문서 근거 답이 나오지 않는다.