feat: align DDS with common permission and vector flow

This commit is contained in:
devmrko
2026-06-29 23:50:42 +09:00
parent ad9a2b7dd4
commit 2e4bcef44f
21 changed files with 1207 additions and 25 deletions

View File

@@ -0,0 +1,101 @@
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(title)">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title th:text="${title}">DDS 백오피스</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/app.css" rel="stylesheet">
<link th:if="${backofficeTrack == 'DDS'}" href="/css/dds.css" rel="stylesheet">
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<script defer src="https://unpkg.com/alpinejs@3.14.8/dist/cdn.min.js"></script>
<script defer src="/js/app.js"></script>
</head>
<body>
<nav th:fragment="nav" class="navbar rw-nav navbar-expand-lg">
<div class="container">
<a class="navbar-brand" href="/" th:text="${backofficeTrack == 'DDS' ? 'DDS Backoffice' : 'VPD Backoffice'}">DDS Backoffice</a>
<span class="badge rounded-pill text-bg-primary ms-2" th:if="${backofficeTrack == 'DDS'}">독립 DDS 트랙 · 8083</span>
<div class="rw-menu">
<div class="rw-menu-group">
<button class="rw-menu-trigger" type="button" aria-expanded="false">1. 권한 설계</button>
<div class="rw-menu-panel">
<a class="nav-link" href="/users">사용자</a>
<a class="nav-link" href="/groups">그룹</a>
<a class="nav-link" href="/roles">역할</a>
<a class="nav-link" href="/permissions">데이터 권한 규칙</a>
<a class="nav-link" href="/effective-matrix">사용자별 최종 권한</a>
</div>
</div>
<div class="rw-menu-group">
<button class="rw-menu-trigger" type="button" aria-expanded="false"
th:text="${backofficeTrack == 'DDS' ? '2. DDS 보호·검증' : '2. 보호·검증'}">2. 보호·검증</button>
<div class="rw-menu-panel">
<a class="nav-link" href="/vpd-policies"
th:text="${backofficeTrack == 'DDS' ? 'DDS 보호 연결' : 'DB 보호 연결'}">DB 보호 연결</a>
<a class="nav-link" href="/tokens" th:if="${backofficeTrack != 'DDS'}">검증 세션 발급</a>
<a class="nav-link" href="/probe" th:if="${backofficeTrack != 'DDS'}">권한 결과 확인</a>
<a class="nav-link" href="/dds">DDS 직접 조회</a>
</div>
</div>
<div class="rw-menu-group">
<button class="rw-menu-trigger" type="button" aria-expanded="false">연동 도구</button>
<div class="rw-menu-panel">
<a class="nav-link" href="/objects" th:if="${backofficeTrack != 'DDS'}">ORDS 조회 대상</a>
<a class="nav-link" href="/ords-handlers" th:if="${backofficeTrack != 'DDS'}">ORDS 핸들러</a>
<a class="nav-link" href="/vector-knowledge">지식 검색 관리</a>
<a class="nav-link" href="/mcp-chatbot" th:if="${backofficeTrack != 'DDS'}">Chatbot</a>
<a class="nav-link" href="/mcp-reasoning" th:if="${backofficeTrack != 'DDS'}">Reasoning</a>
<a class="nav-link" href="/mcp-sse" th:if="${backofficeTrack != 'DDS'}">SSE 서비스</a>
<a class="nav-link" href="/mcp-client-demo" th:if="${backofficeTrack != 'DDS'}">MCP Client</a>
</div>
</div>
<div class="rw-menu-group">
<button class="rw-menu-trigger" type="button" aria-expanded="false">운영·고급</button>
<div class="rw-menu-panel">
<a class="nav-link" href="/operation-status" th:if="${backofficeTrack != 'DDS'}">운영 상태</a>
<a class="nav-link" href="/vpd-filter-policies" th:if="${backofficeTrack != 'DDS'}">별도 Filter 관리</a>
<a class="nav-link" href="/settings" th:if="${backofficeTrack != 'DDS'}">설정</a>
</div>
</div>
</div>
<form method="post" action="/logout" class="ms-auto">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
<button class="btn btn-sm btn-outline-secondary" type="submit">로그아웃</button>
</form>
</div>
</nav>
<div th:fragment="trackNotice" th:if="${backofficeTrack == 'DDS'}" class="container pt-3">
<div class="alert alert-info mb-0">
<strong>DDS 독립 데모</strong> · VPD와 같은 관리 흐름을 사용하지만, 실제 보호 적용은 <code>END USER → DATA ROLE → DATA GRANT</code>로 별도 처리합니다.
</div>
</div>
<section th:fragment="architectureStrip(activeLayer)" class="architecture-strip" aria-label="권한 설정부터 결과 확인까지의 흐름">
<div class="architecture-step" th:classappend="${activeLayer == 'permission'} ? ' active'">
<span class="architecture-kicker">1 · WHO / WHAT</span>
<strong>권한 설계</strong>
<p>누가 어떤 데이터의 어느 행과 컬럼을 볼지 정합니다.</p>
</div>
<div class="architecture-arrow"></div>
<div class="architecture-step" th:classappend="${activeLayer == 'vpd'} ? ' active'">
<span class="architecture-kicker" th:text="${backofficeTrack == 'DDS' ? '2 · ENFORCE' : '2 · ENFORCE'}">2 · ENFORCE</span>
<strong th:text="${backofficeTrack == 'DDS' ? 'DDS 보호 연결' : 'DB 보호 연결'}">DB 보호 연결</strong>
<p th:text="${backofficeTrack == 'DDS' ? 'DATA ROLE과 DATA GRANT가 관리된 권한을 보호 객체에 선언합니다.' : 'VPD가 저장된 권한체계를 매번 읽어 DB에서 행을 자동 제한합니다.'}">DB 보호 정책이 권한을 적용합니다.</p>
</div>
<div class="architecture-arrow"></div>
<div class="architecture-step" th:classappend="${activeLayer == 'token'} ? ' active'">
<span class="architecture-kicker">3 · IDENTITY</span>
<strong th:text="${backofficeTrack == 'DDS' ? 'END USER 컨텍스트' : '검증 세션'}">검증 세션</strong>
<p th:text="${backofficeTrack == 'DDS' ? 'DDS END USER 또는 지원 드라이버 컨텍스트로 조회 주체를 전달합니다.' : '확인할 사용자를 나타내는 일회성 토큰을 준비합니다.'}">조회 주체를 준비합니다.</p>
</div>
<div class="architecture-arrow"></div>
<div class="architecture-step" th:classappend="${activeLayer == 'ords'} ? ' active'">
<span class="architecture-kicker">4 · EVIDENCE</span>
<strong>결과 확인</strong>
<p>보호 정책을 통과한 데이터만 실제 결과로 확인합니다.</p>
</div>
</section>
</body>
</html>