Compare commits

..

2 Commits

Author SHA1 Message Date
devmrko
ef7a855462 docs: trace sales knowledge scenario 2026-06-30 14:29:58 +09:00
devmrko
fb93781925 [Developer] #571 show VPD context in SQL trace 2026-06-30 14:29:54 +09:00
5 changed files with 71 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
# 설계서: 기술 태그 기반 벡터 지식자료 검색과 VPD 연결 # 설계서: 기술 태그 기반 벡터 지식자료 검색과 VPD 연결
> **상태**: 제품형 운영 흐름 구현 · DDS 병행 검증 완료 · 객체별 Data Grant predicate 적용 · 운영 확장 항목 별도 > **상태**: 제품형 운영 흐름 구현 · DDS 병행 검증 완료 · 객체별 Data Grant predicate 적용 · 운영 확장 항목 별도
> **추적성**: Redmine #565, #566 · 구현 커밋 `a5e70bc` · 기준 구현: `28_agent_ords_vector_tag_vpd_setup.sql`, `29_agent_ords_vector_search_ords.sql`, `32_dds_vector_tag_setup.sql`, `34_dds_token_data_grant_common_auth.sql`, `36_dds_sales_knowledge_scenario.sql` > **추적성**: Redmine #565, #566 · 구현 커밋 `a5e70bc`, `04cca64`, `8978be4` · 기준 구현: `28_agent_ords_vector_tag_vpd_setup.sql`, `29_agent_ords_vector_search_ords.sql`, `32_dds_vector_tag_setup.sql`, `34_dds_token_data_grant_common_auth.sql`, `36_dds_sales_knowledge_scenario.sql`
## 1. 한 문장으로 이해하기 ## 1. 한 문장으로 이해하기

View File

@@ -1,7 +1,7 @@
# 독립 VPD·DDS 데모 구성 # 독립 VPD·DDS 데모 구성
> **상태**: VPD·DDS 병행 검증 완료, 토큰 기반 객체별 Data Grant 적용 완료 > **상태**: VPD·DDS 병행 검증 완료, 토큰 기반 객체별 Data Grant 적용 완료
> **추적성**: Redmine #565, #566 · DDS 구현 커밋 `1e48864`, `a5e70bc` > **추적성**: Redmine #565, #566 · DDS 구현 커밋 `1e48864`, `a5e70bc`, `04cca64`, `8978be4`
> **기준 구현**: `sql/adb/32_dds_vector_tag_setup.sql`, `sql/adb/34_dds_token_data_grant_common_auth.sql`, `sql/adb/36_dds_sales_knowledge_scenario.sql`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsGrantPublisher.java`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsVectorKnowledgeService.java` > **기준 구현**: `sql/adb/32_dds_vector_tag_setup.sql`, `sql/adb/34_dds_token_data_grant_common_auth.sql`, `sql/adb/36_dds_sales_knowledge_scenario.sql`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsGrantPublisher.java`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsVectorKnowledgeService.java`
## 목적 ## 목적

View File

@@ -0,0 +1,47 @@
# 설계서: 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가 같은 결과 카드에 표시되는지 확인한다.

View File

@@ -117,6 +117,26 @@
<span class="badge text-bg-light">DBMS_RLS predicate</span> <span class="badge text-bg-light">DBMS_RLS predicate</span>
</div> </div>
<div class="probe-exchange-grid mt-3"> <div class="probe-exchange-grid mt-3">
<section class="probe-exchange" data-sql-trace-field="vpd_context" th:if="${tokenContext}">
<h3>set_vpd_context 사용자 컨텍스트</h3>
<p class="form-hint">이 컨텍스트로 권한 규칙을 계산한 뒤 아래 VPD predicate와 effective SQL을 만들었습니다.</p>
<dl class="mb-0">
<div><dt>CB_AGENT_CTX.USER_ID</dt><dd th:text="${tokenContext.userId()}">103</dd></div>
<div><dt>사용자</dt><dd th:text="${tokenContext.username()}">agent_all</dd></div>
<div>
<dt>직접 역할</dt>
<dd th:text="${#lists.isEmpty(tokenContext.directRoles()) ? '없음' : #strings.listJoin(tokenContext.directRoles(), ', ')}">ALL_DOC_ROLE</dd>
</div>
<div>
<dt>소속 그룹</dt>
<dd th:text="${#lists.isEmpty(tokenContext.groups()) ? '없음' : #strings.listJoin(tokenContext.groups(), ', ')}">없음</dd>
</div>
<div>
<dt>상속 역할</dt>
<dd th:text="${#lists.isEmpty(tokenContext.inheritedRoles()) ? '없음' : #strings.listJoin(tokenContext.inheritedRoles(), ', ')}">없음</dd>
</div>
</dl>
</section>
<section class="probe-exchange" data-sql-trace-field="vpd_predicate"> <section class="probe-exchange" data-sql-trace-field="vpd_predicate">
<h3>VPD가 추가한 WHERE 조건</h3> <h3>VPD가 추가한 WHERE 조건</h3>
<pre th:text="${result.vpdPredicate()}">(DEPT_CODE = SYS_CONTEXT('CB_AGENT_CTX', 'DEPT_CODE'))</pre> <pre th:text="${result.vpdPredicate()}">(DEPT_CODE = SYS_CONTEXT('CB_AGENT_CTX', 'DEPT_CODE'))</pre>

View File

@@ -35,6 +35,8 @@ class GuidedFlowTemplateTest {
assertThat(result) assertThat(result)
.contains("적용된 사용자와 권한") .contains("적용된 사용자와 권한")
.contains("토큰 적용 후 SQL") .contains("토큰 적용 후 SQL")
.contains("set_vpd_context 사용자 컨텍스트")
.contains("CB_AGENT_CTX.USER_ID")
.contains("벡터 검색 Top-K") .contains("벡터 검색 Top-K")
.contains("벡터 거리 (SCORE)") .contains("벡터 거리 (SCORE)")
.contains("vpd_predicate") .contains("vpd_predicate")