# 설계서: SQL trace의 set_vpd_context 사용자 컨텍스트 표시 (#571) > **상태**: Approved > **작성**: [AI] Architect · **최종수정**: 2026-06-30 > **추적성** — Redmine: #571 · 선행 기능: #567, #570 > · 구현 파일: `probe-result.html`, `TokenContextView`, `ProbeController` > · 테스트: `GuidedFlowTemplateTest`, `mvn test` ## 1. 목적 권한 적용 SQL trace에서 최종 predicate만 보여 사용자와 predicate의 연결이 끊겨 보이는 문제를 해결한다. `set_vpd_context`가 설정한 `CB_AGENT_CTX.USER_ID`와 백오피스가 해석한 사용자·역할·그룹을 predicate 앞에 표시해 다음 흐름을 한 화면에서 증명한다. ```text Bearer Token → set_vpd_context → CB_AGENT_CTX.USER_ID = 사용자 ID → 사용자/역할/그룹 권한 규칙 조회 → VPD predicate → effective SQL ``` ## 2. 설계 원칙 - SQL에 `AND USER_ID = ...` 같은 가짜 조건을 추가하지 않는다. 벡터 검색 대상에는 `USER_ID` 컬럼이 없고, 실제 VPD 함수는 사용자 context로 권한 규칙을 계산한 뒤 대상 데이터의 `TECH_TAG` predicate를 반환한다. - context는 실제 토큰에서 해석된 `TokenContextView`를 사용한다. Bearer 원문은 표시하지 않는다. - `USER_ID`, 사용자명, 직접 역할, 그룹, 상속 역할은 trace 영역의 “set_vpd_context 사용자 컨텍스트” 카드에 표시한다. - 아래 VPD predicate는 바로 위 context에서 계산된 결과라는 설명을 명시한다. ## 3. 인수조건 - [ ] `토큰 적용 후 SQL`에 `CB_AGENT_CTX.USER_ID`와 사용자명이 표시된다. - [ ] 직접 역할·그룹·상속 역할이 context 카드에서 확인된다. - [ ] context → `VPD가 추가한 WHERE 조건` → `권한 적용 SQL` 순서가 화면에 보인다. - [ ] SQL 본문에 실제 존재하지 않는 `USER_ID` 조건을 삽입하지 않는다. - [ ] invalid/inactive token처럼 context가 없을 때는 기존 “토큰에서 사용자를 찾지 못함” 안내를 유지한다. - [ ] Bearer 원문과 임베딩 숫자는 context 카드에 표시하지 않는다. - [ ] 전체 Maven 테스트와 실제 vector probe smoke가 통과한다. ## 4. 화면 계약 `TokenContextView.userId()`를 `CB_AGENT_CTX.USER_ID` 값으로 표시하고, `username`, `directRoles`, `groups`, `inheritedRoles`를 사람이 읽을 수 있는 label로 표시한다. predicate와 effective SQL은 기존 `ProbeResult` 필드를 그대로 사용한다. ## 5. 검증 - 템플릿 테스트에서 `set_vpd_context 사용자 컨텍스트`, `CB_AGENT_CTX.USER_ID`, `VPD가 추가한 WHERE 조건`, `권한 적용 SQL`을 확인한다. - `mvn test`. - vector `/probe`에서 `agent_all` 또는 선택 사용자의 ID/역할과 TAG predicate가 같은 결과 카드에 표시되는지 확인한다.