From f15b453aadfeb52c0fdc24c4802b2c3abf3d7f74 Mon Sep 17 00:00:00 2001 From: devmrko Date: Wed, 1 Jul 2026 10:35:21 +0900 Subject: [PATCH] [UX] #577 simplify VPD product forms --- docs/design/577-persona-ux-audit/README.md | 12 +++- src/main/resources/static/css/app.css | 50 ++++++++++++- .../resources/templates/mcp-client-demo.html | 6 +- .../resources/templates/operation-status.html | 2 +- src/main/resources/templates/permissions.html | 71 ++++++++----------- src/main/resources/templates/probe.html | 12 ++-- src/main/resources/templates/tokens.html | 4 +- .../resources/templates/vpd-policies.html | 30 +------- .../web/GuidedFlowTemplateTest.java | 22 ++++++ 9 files changed, 128 insertions(+), 81 deletions(-) diff --git a/docs/design/577-persona-ux-audit/README.md b/docs/design/577-persona-ux-audit/README.md index 75aeea8..bc49dd8 100644 --- a/docs/design/577-persona-ux-audit/README.md +++ b/docs/design/577-persona-ux-audit/README.md @@ -104,6 +104,16 @@ UX-1부터 시작한다. 기존 데이터 모델과 VPD 로직은 바꾸지 않 | 별도 Filter 관리 | 고급 접근 조건 | 예외 정책 기능 | | 운영 상태 / 연결 설정 | 운영 현황 / 시스템 설정 | 운영성·연동 설정 기능 | -상단 메뉴는 DDS와 같은 네 업무 영역인 `권한 관리 · 보호 정책 관리 · 지식자료 관리 · 접근 검증`으로 구성한다. ORDS·MCP·Filter·시스템 설정은 기본 제품 메뉴에서 빼고 관련 화면의 고급 링크에서만 연다. 첫 줄에는 제품명·1차 메뉴·로그아웃을 함께 둔다. 1차 메뉴를 누르면 하위 메뉴가 팝업으로 뜨지 않고 바로 아래 전폭 줄에 표시된다. 현재 페이지가 속한 메뉴는 처음부터 아래 줄을 열어 둔다. 절차나 구현 방식이 아니라 사용자가 하려는 일을 메뉴명으로 쓴다. 메뉴와 기본 화면에는 `1.`, `2.`, 단계 레일, `01/02` 배지를 두지 않는다. 순서가 실제 입력 제약인 wizard에서만 단계 번호를 사용한다. +상단 메뉴는 DDS와 같은 네 업무 영역인 `권한 관리 · 보호 정책 관리 · 지식자료 관리 · 접근 검증`으로 구성한다. ORDS·MCP·Filter·시스템 설정은 기본 제품 메뉴에서 빼고 관련 화면의 고급 링크에서만 연다. 첫 줄에는 제품명·1차 메뉴·로그아웃을 함께 둔다. 1차 메뉴를 누르면 하위 메뉴가 팝업으로 뜨지 않고 바로 아래 전폭 줄에 표시된다. 현재 페이지가 속한 메뉴는 처음부터 아래 줄을 열어 둔다. 절차나 구현 방식이 아니라 사용자가 하려는 일을 메뉴명으로 쓴다. 메뉴와 기본 화면, wizard에도 `1.`, `2.`, 단계 레일, `01/02` 배지를 두지 않는다. 선택된 입력 영역은 역할·대상·접근 범위처럼 의미 있는 이름으로만 표시한다. 기본 페이지는 제목과 현재 설정·주요 행동만 노출한다. VPD/ORDS 처리 원리, 배경 설명, 주의사항은 상단의 공통 `도움말` 버튼을 눌렀을 때만 펼친다. 이 규칙으로 제품 화면이 관리 매뉴얼처럼 보이는 문제를 줄이고, 설정 자체를 전면에 둔다. + +## 9. 화면 캡처 기반 정리 — 2026-07-01 + +로그인된 브라우저로 홈, 권한 주체·규칙·현황, 보호 상태·대상, 검증 세션·접근 검증·운영 현황, 지식자료·대화형 검색·검색 해석, 고급·설정 화면을 데스크톱 기준으로 캡처해 확인했다. MCP SSE와 Java client 화면은 데이터 조회 대기 때문에 브라우저 캡처를 완료하지 못했으며, 동일 템플릿·공통 레이아웃과 정적 화면 구조를 별도로 점검했다. + +- 1차 메뉴는 첫 줄, 현재 업무 영역의 하위 메뉴는 둘째 줄에 나타나는 구조를 실제 사용자 관리 화면에서 확인했다. +- 기본 화면에 남아 있던 단계 번호를 역할·대상·접근 범위 같은 작업명으로 바꾸고, 검증 세션·접근 검증·연동 점검에서도 순번을 제거한다. +- 접근 규칙 목록은 ID·고정 ACTION·삭제 경고를 기본 열에서 빼고, 필요한 삭제 영향만 행의 `관리` 상세에서 확인하게 한다. +- 보호 상태의 동작 설명은 상단 도움말로 옮기고, 기본 화면은 보호 대상과 적용 작업부터 보이게 한다. +- 운영 현황은 긴 ORDS·VPD 값 때문에 오른쪽 열이 밀리지 않도록 고정 열 폭과 줄바꿈을 적용한다. diff --git a/src/main/resources/static/css/app.css b/src/main/resources/static/css/app.css index 9871e0d..e83b5de 100644 --- a/src/main/resources/static/css/app.css +++ b/src/main/resources/static/css/app.css @@ -647,7 +647,6 @@ body { .wizard-panel-heading { align-items: flex-start; display: flex; - gap: .75rem; } .wizard-panel-heading h3 { @@ -1369,6 +1368,55 @@ body { white-space: pre-wrap; } +.permission-list-table { + min-width: 760px; +} + +.permission-list-table th:nth-child(1) { width: 15%; } +.permission-list-table th:nth-child(2) { width: 19%; } +.permission-list-table th:nth-child(3) { width: 10%; } +.permission-list-table th:nth-child(4) { width: 24%; } +.permission-list-table th:nth-child(5) { width: 16%; } +.permission-list-table th:nth-child(6) { width: 16%; } + +.row-management { + min-width: 10rem; +} + +.row-management > summary { + color: var(--rw-primary); + cursor: pointer; + font-size: .84rem; + font-weight: 800; +} + +.row-management[open] { + background: var(--rw-surface-muted); + border: 1px solid var(--rw-border); + border-radius: 8px; + padding: .65rem; +} + +.operation-status-table { + table-layout: fixed; + width: 100%; +} + +.operation-status-table th, +.operation-status-table td, +.operation-status-table code { + overflow-wrap: anywhere; + white-space: normal; +} + +.operation-status-table th:nth-child(1) { width: 5%; } +.operation-status-table th:nth-child(2) { width: 22%; } +.operation-status-table th:nth-child(3) { width: 29%; } +.operation-status-table th:nth-child(4) { width: 20%; } +.operation-status-table th:nth-child(5) { width: 10%; } +.operation-status-table th:nth-child(6) { width: 9%; } +.operation-status-table th:nth-child(7) { width: 5%; } + .schema-summary { display: grid; gap: .75rem; diff --git a/src/main/resources/templates/mcp-client-demo.html b/src/main/resources/templates/mcp-client-demo.html index e3544fa..90c7286 100644 --- a/src/main/resources/templates/mcp-client-demo.html +++ b/src/main/resources/templates/mcp-client-demo.html @@ -36,17 +36,17 @@
- 1 + 연결 시작 initialize 기본 MCP serverInfo와 tools capability를 확인합니다.
- 2 + 도구 목록 tools/list 현재 보호 객체에서 생성된 ORDS query tool과 설명/schema를 조회합니다.
- 3 + 도구 호출 tools/call tool 선택은 reasoning 이후 MCP client가 수행하므로 이 화면에서는 호출하지 않습니다.
diff --git a/src/main/resources/templates/operation-status.html b/src/main/resources/templates/operation-status.html index bb30d8b..bd31b68 100644 --- a/src/main/resources/templates/operation-status.html +++ b/src/main/resources/templates/operation-status.html @@ -14,7 +14,7 @@
- +
diff --git a/src/main/resources/templates/permissions.html b/src/main/resources/templates/permissions.html index 4fc5a11..e783d46 100644 --- a/src/main/resources/templates/permissions.html +++ b/src/main/resources/templates/permissions.html @@ -22,11 +22,11 @@

저장 전 적용 대상과 행 범위를 검토한 뒤 VPD 권한을 반영합니다.

- - - - - + + + + +
@@ -61,7 +61,6 @@
- 1

역할 선택

권한을 부여하거나 거부할 역할을 선택합니다.

@@ -96,7 +95,6 @@
- 2

보호 객체 선택

등록된 보호 객체 또는 DB 스키마 객체를 선택합니다.

@@ -138,7 +136,6 @@
- 3

권한 효과와 행 규칙

허용/거부 방향과 VPD 행 필터 조건을 설정합니다.

@@ -186,7 +183,6 @@
- 4

권한별 원문 표시 예외

이 역할이 이미 볼 수 있는 행에서 마스킹을 제외할 컬럼을 여러 개 선택합니다.

@@ -211,7 +207,6 @@
- 5

저장 전 검토

저장될 권한과 예상 effective policy를 확인합니다.

@@ -245,56 +240,52 @@

접근 규칙 목록

-
Health
+
- - - - - - - - - + + + + + - - - - + - - +
ID 역할테이블/뷰ActionEffect행 규칙적용 필터원문 표시 허용 컬럼(여러 개)삭제 영향보호 대상효과접근 범위표시 예외관리
100 HR_DEPT_ROLE CB_V_SEARCH_DOCUMENTSSELECT ALLOW ALL
ALL ROWS
ALL ROWS
CONTENTS - 역할이 이 TABLE/VIEW의 SELECT 권한을 잃습니다. - ROLE -> OBJECT - 이 객체의 마지막 권한입니다. 삭제 후 보호 객체가 비활성화됩니다. - 같은 객체에 다른 역할 권한이 남아 있습니다. - - - - - - - +
+ 관리 +
+ 이 역할은 이 대상의 SELECT 권한을 잃습니다. + ROLE → OBJECT + 마지막 권한입니다. 삭제 후 보호 대상이 비활성화될 수 있습니다. + 같은 대상에 다른 역할 권한이 남아 있습니다. +
+
+ + + + +
+
등록된 권한이 없습니다.등록된 접근 규칙이 없습니다.
diff --git a/src/main/resources/templates/probe.html b/src/main/resources/templates/probe.html index 48c54d5..f0efaf8 100644 --- a/src/main/resources/templates/probe.html +++ b/src/main/resources/templates/probe.html @@ -35,7 +35,7 @@
- +
diff --git a/src/main/resources/templates/vpd-policies.html b/src/main/resources/templates/vpd-policies.html index 08fbf27..245d1e9 100644 --- a/src/main/resources/templates/vpd-policies.html +++ b/src/main/resources/templates/vpd-policies.html @@ -8,7 +8,7 @@

보호 상태

도움말 -

권한 화면에서 만든 사용자·그룹·역할·행·열 규칙을 Oracle VPD가 실제 TABLE/VIEW에 적용하도록 연결합니다.

+

권한 화면에서 만든 사용자·그룹·역할·행·열 규칙을 Oracle VPD가 실제 TABLE/VIEW에 적용하도록 연결합니다. Policy는 어느 객체의 어떤 SQL에 어떤 Filter function을 붙일지 정하고, 실제 허용 조건은 권한 규칙과 Filter가 계산합니다.

@@ -22,32 +22,8 @@
- 기본 동작 -

권한체계 자동 적용

-
- 권한 규칙 확인 -
-
- 사용자·그룹·역할 - - 객체별 행·열 권한 - - 동적 VPD - - 허용된 데이터만 반환 -
-

CB_AGENT_DOC_VPD_FILTER가 요청마다 권한체계를 읽습니다. 일반 변경은 권한 규칙에서 합니다.

-
- Policy와 Filter의 역할 구분 보기 -

Policy는 “어느 객체의 어떤 SQL에 어떤 Filter function을 붙일지”를 정합니다. 행의 실제 허용/차단 조건은 권한 규칙과 Filter function이 계산하고, 컬럼 표시 보호는 별도 설정입니다.

-
-
- -
-
-
-

보호할 수 있는 DB 객체

-

VPD 적용 상태와 권한·검증 경로를 확인합니다.

+

보호 대상

+

VPD 적용과 검증 준비 상태를 확인합니다.

객체 상태 항목 설명 보기

VPD가 붙었는지, 권한 규칙과 검증 경로가 준비됐는지 한곳에서 확인합니다. 아래 기본 적용에서는 객체만 선택하면 됩니다.

diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java b/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java index 4f210c4..d82533b 100644 --- a/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java +++ b/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java @@ -59,6 +59,28 @@ class GuidedFlowTemplateTest { .doesNotContain("1 · CONTENT", "2 · ACCESS POLICY", "3 · SEARCH"); } + @Test + void productFormsUseTaskNamesInsteadOfVisibleStepNumbers() throws IOException { + String permissions = template("permissions.html"); + String tokens = template("tokens.html"); + String probe = template("probe.html"); + String client = template("mcp-client-demo.html"); + + assertThat(permissions) + .contains("data-wizard-target=\"1\">역할") + .contains("data-wizard-target=\"2\">대상") + .doesNotContain(">1 역할<", ">2 객체<", "wizard-step-number"); + assertThat(tokens) + .contains("검증 사용자 선택", "검증 세션 발급") + .doesNotContain("1. 검증할 사용자 선택", "2. 검증 세션 발급"); + assertThat(probe) + .contains("접근 검증 실행", "검증 결과") + .doesNotContain("1. 발급받은 토큰 원문", "2. 확인할 데이터", "3. 접근 검증 실행"); + assertThat(client) + .contains("연결 시작", "도구 목록", "도구 호출") + .doesNotContain("1", "2", "3"); + } + @Test void probeUsesOneTokenInputAndHidesTechnicalExchangeByDefault() throws IOException { String probe = template("probe.html");