<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/layout :: head('정책 적용')}"></head>
<body>
<nav th:replace="~{fragments/layout :: nav}"></nav>
<main class="container py-4">
  <div class="page-title">
    <span class="architecture-kicker">DDS · PUBLISH</span>
    <h1>보호 정책 적용</h1>
    <p class="context-summary">사용자·그룹·역할의 접근 규칙을 검토한 뒤 DDS 보호 규칙에 반영합니다.</p>
    <details class="explanation-details">
      <summary>도움말</summary>
      <p>게시하면 직접 DDS 비교 Grant와 MCP SSE용 local END USER/DATA ROLE/DATA GRANT를 함께 갱신합니다. MCP 요청 Bearer는 기존 사용자 테이블의 업무 사용자를 찾고, DDS는 그 사용자의 게시된 권한만 집행합니다.</p>
      <p class="mb-0">OCI IAM client-credentials token은 서비스의 Context attach 권한만 제공합니다. MCP 업무 사용자를 IAM에 따로 만들지 않으며, 그룹 역할 상속은 기존 권한 관리 기준으로 계산합니다.</p>
    </details>
  </div>

  <section th:replace="~{fragments/layout :: architectureStrip('publish')}"></section>

  <section class="content-band">
    <details class="explanation-details">
      <summary>도움말</summary>
      <div class="table-responsive mt-3">
        <table class="table table-sm align-middle mb-0">
          <thead><tr><th>공통 권한 관리</th><th>DDS에서의 표현</th><th>반영 시점</th></tr></thead>
          <tbody>
          <tr><td>애플리케이션 사용자</td><td>매핑된 DDS END USER + DATA ROLE</td><td>게시할 때 매핑 확인</td></tr>
          <tr><td>그룹과 그룹에 연결된 역할</td><td>그룹을 복사하지 않고 최종 predicate로 합산</td><td>미리보기·게시 때 계산</td></tr>
          <tr><td>테이블·VIEW SELECT 권한</td><td>보호 객체별 <code>DATA GRANT ... WHERE ...</code></td><td>권한 변경 후 게시</td></tr>
          <tr><td>MCP Bearer 벡터 검색</td><td>Bearer → 업무 사용자 → local DDS END USER Context → DATA GRANT</td><td>권한 저장 시 자동 bulk 동기화 · 이 화면은 전체 재동기화</td></tr>
          <tr><td>원문 표시 허용 컬럼</td><td><code>AS SELECT</code> 또는 <code>ALL COLUMNS EXCEPT</code></td><td>권한 변경 후 게시</td></tr>
          </tbody>
        </table>
      </div>
      <p class="text-muted mt-3 mb-0">DDS는 게시된 Grant가 바뀔 때까지 이전 선언을 사용합니다. 이 화면의 게시 버튼이 기존 권한 관리와 MCP local END USER 권한을 동기화하는 경계입니다.</p>
    </details>
  </section>

  <div class="alert alert-success" th:if="${successMessage}" th:text="${successMessage}"></div>
  <div class="alert alert-warning" th:if="${warningMessage}" th:text="${warningMessage}"></div>
  <div class="alert alert-danger" th:if="${errorMessage}" th:text="${errorMessage}"></div>

  <section class="content-band">
    <div class="section-heading">
      <div>
        <span class="architecture-kicker">변경 검토</span>
        <h2>게시 전 변경 내용</h2>
        <p class="section-subtitle">직접 부여된 역할과 활성 그룹의 역할을 합쳐 보호 규칙을 만듭니다.</p>
      </div>
      <span class="badge text-bg-secondary" th:text="${plan.mappedUserCount() + '명 매핑'}">0명 매핑</span>
    </div>
    <div class="alert alert-info" th:if="${plan.publishableCount() == 0}">
      게시할 접근 허용 규칙이 없습니다. 보호 객체 매핑과 접근 규칙을 먼저 확인하세요.
    </div>
    <form method="post" action="/dds-provision/publish" class="mb-3" th:if="${plan.publishableCount() > 0}">
      <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
      <button class="btn rw-btn-primary" type="submit"
              onclick="return confirm('현재 미리보기대로 보호 규칙을 게시하고 더 이상 허용되지 않는 규칙을 회수할까요?')">변경 내용 게시</button>
    </form>
    <div class="table-responsive">
      <table class="table table-sm align-middle">
        <thead><tr><th>접근 주체</th><th>관리 대상</th><th>보호 대상</th><th>판정</th><th>접근 조건</th><th>제한 컬럼</th></tr></thead>
        <tbody>
        <tr th:each="grant : ${plan.grants()}">
          <td><strong th:text="${grant.userLabel()}">사용자</strong><small class="d-block text-muted" th:text="${'userId=' + grant.applicationUserId() + ' · ' + grant.dataRole()}">mapping</small></td>
          <td><code th:text="${grant.applicationObject()}">CB_VECTOR_SEARCH_DOCUMENTS</code></td>
          <td><code th:text="${grant.ddsObject()}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code><small class="d-block text-muted" th:text="${grant.grantName()}">GRANT</small></td>
          <td>
            <span class="badge text-bg-success" th:if="${grant.publishable()}">게시 가능</span>
            <span class="badge text-bg-warning" th:unless="${grant.publishable()}">검토 필요</span>
            <small class="d-block text-muted" th:text="${grant.note()}">메모</small>
          </td>
          <td><code th:text="${grant.predicate() ?: '-'}">predicate</code></td>
          <td th:text="${grant.excludedColumns() ?: '없음'}">없음</td>
        </tr>
        <tr th:if="${#lists.isEmpty(plan.grants())}"><td colspan="6" class="text-muted">현재 접근 규칙에서 게시할 보호 대상을 찾지 못했습니다.</td></tr>
        </tbody>
      </table>
    </div>
  </section>

  <section class="content-band" th:if="${plan.hasWarnings()}">
    <div class="section-heading"><div><h2>게시 전 확인할 항목</h2><p class="section-subtitle">지원되지 않는 객체나 매핑 누락은 게시하지 않고 경고로 남깁니다.</p></div></div>
    <ul>
      <li th:each="warning : ${plan.warnings()}" th:text="${warning}">경고</li>
    </ul>
  </section>

  <section class="content-band" th:if="${plan.publishableCount() > 0}">
    <details class="explanation-details">
      <summary>기술 상세</summary>
      <div th:each="grant : ${plan.grants()}" th:if="${grant.publishable()}" class="mt-3">
        <strong th:text="${grant.grantName()}">GRANT</strong>
        <pre class="code-block" th:text="${grant.sql()}">CREATE OR REPLACE DATA GRANT ...</pre>
      </div>
    </details>
  </section>
</main>
</body>
</html>
