refs #702: externalize HMM structured data catalog

This commit is contained in:
devmrko
2026-07-23 10:43:54 +09:00
parent eb5105fe72
commit 9e3840a4d7
23 changed files with 495 additions and 136 deletions

View File

@@ -108,8 +108,8 @@
<thead><tr><th>보호 객체</th><th>DB 정책</th><th>백오피스 활성 컬럼</th><th>DB Redaction 컬럼</th><th>레거시 VPD 컬럼 제어</th><th>DB 정책 활성</th><th>상태 판단</th></tr></thead>
<tbody>
<tr th:each="status : ${policyStatuses}">
<td><code th:text="${status.targetLabel()}">POC_2.KB_CUSTOMERS</code></td>
<td><code th:text="${status.policyName()}">KB_CUSTOMER_PII_REDACT</code></td>
<td><code th:text="${status.targetLabel()}">ADMIN.HMM_HR_EMPLOYEES</code></td>
<td><code th:text="${status.policyName()}">HMM_EMPLOYEE_PII_REDACT</code></td>
<td th:text="${status.configuredColumnCount()}">0</td>
<td th:text="${status.appliedColumnCount()}">0</td>
<td><span class="badge" th:classappend="${status.legacyVpdColumnPolicyCount() == 0} ? ' text-bg-secondary' : ' text-bg-danger'" th:text="${status.legacyVpdColumnPolicyCount() == 0} ? '없음' : ${status.legacyVpdColumnPolicyCount() + '건 활성'}">없음</span></td>
@@ -142,12 +142,12 @@
<section class="content-band">
<h2>컬럼 마스킹 규칙 등록</h2>
<p class="section-subtitle">업무용 이름을 붙여 템플릿을 재사용합니다. 예: <code>KB_RRN_STANDARD</code>.</p>
<p class="section-subtitle">업무용 이름을 붙여 템플릿을 재사용합니다. 예: <code>HMM_EMAIL_STANDARD</code>.</p>
<form method="post" action="/masking-rules" class="form-grid">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
<label>
규칙 코드
<input class="form-control" name="ruleCode" maxlength="64" pattern="[A-Za-z][A-Za-z0-9_]{2,63}" required placeholder="KB_RRN_STANDARD">
<input class="form-control" name="ruleCode" maxlength="64" pattern="[A-Za-z][A-Za-z0-9_]{2,63}" required placeholder="HMM_EMAIL_STANDARD">
<span class="form-hint">영문·숫자·밑줄만 사용합니다.</span>
</label>
<label>
@@ -176,7 +176,7 @@
<thead><tr><th>코드</th><th>규칙명</th><th>템플릿</th><th>설명</th><th>상태</th><th></th></tr></thead>
<tbody>
<tr th:each="rule : ${rules}">
<td><code th:text="${rule.ruleCode()}">KB_RRN_STANDARD</code></td>
<td><code th:text="${rule.ruleCode()}">HMM_EMAIL_STANDARD</code></td>
<td th:text="${rule.ruleName()}">주민번호 기본 마스킹</td>
<td th:text="${rule.templateLabel()}">값 숨김(NULL)</td>
<td th:text="${rule.description() ?: '-'}">설명</td>
@@ -209,11 +209,11 @@
<optgroup th:label="${object.displayName()}" th:if="${!#lists.isEmpty(availableMaskingColumnsByObject[object.objectId()])}">
<option th:each="columnName : ${availableMaskingColumnsByObject[object.objectId()]}"
th:value="|${object.objectId()}:${columnName}|"
th:text="${object.displayName() + '.' + columnName}">POC_2.KB_CONTRACTS.PREMIUM</option>
th:text="${object.displayName() + '.' + columnName}">ADMIN.HMM_HR_EMPLOYEES.EMAIL</option>
</optgroup>
</th:block>
</select>
<span class="form-hint">현재 관리 대상 ASO 정책이 있는 객체만 표시됩니다. 예: <code>POC_2.KB_CONTRACTS.PREMIUM</code>.</span>
<span class="form-hint">현재 JSON 카탈로그에 관리 대상 ASO 정책이 있는 객체만 표시됩니다. 예: <code>ADMIN.HMM_HR_EMPLOYEES.EMAIL</code>.</span>
</label>
<button class="btn btn-outline-primary" type="submit">대상 컬럼 추가</button>
</form>
@@ -253,7 +253,7 @@
<thead><tr><th>대상 컬럼</th><th>규칙</th><th>템플릿</th><th>백오피스 설정</th><th>DB ASO 적용 상태</th><th></th></tr></thead>
<tbody>
<tr th:each="columnRule : ${columnRules}">
<td><code th:text="${columnRule.targetLabel()}">POC_2.KB_CUSTOMERS.RRN_MASKED</code></td>
<td><code th:text="${columnRule.targetLabel()}">ADMIN.HMM_HR_EMPLOYEES.EMAIL</code></td>
<td th:text="${columnRule.ruleName()}">주민번호 기본 마스킹</td>
<td th:text="${columnRule.template().label()}">주민등록번호 부분 마스킹</td>
<td><span class="badge" th:classappend="${columnRule.ruleEnabled()} ? ' text-bg-success' : ' text-bg-warning'" th:text="${columnRule.ruleEnabled()} ? '기본 규칙 연결됨' : '규칙 비활성'">기본 규칙 연결됨</span></td>

View File

@@ -159,8 +159,8 @@
<thead><tr><th>보호 객체</th><th>DB 정책</th><th>백오피스 활성 컬럼</th><th>DB Redaction 컬럼</th><th>상태</th><th>확인 결과</th></tr></thead>
<tbody>
<tr th:each="status : ${maskingPolicyStatuses}">
<td><code th:text="${status.targetLabel()}">POC_2.KB_CLAIMS</code></td>
<td><code th:text="${status.policyName()}">KB_CLAIM_AMOUNT_REDACT</code></td>
<td><code th:text="${status.targetLabel()}">ADMIN.HMM_HR_EMPLOYEES</code></td>
<td><code th:text="${status.policyName()}">HMM_EMPLOYEE_PII_REDACT</code></td>
<td th:text="${status.configuredColumnCount()}">0</td>
<td th:text="${status.appliedColumnCount()}">0</td>
<td><span class="badge" th:classappend="${' ' + status.badgeClass()}" th:text="${status.statusLabel()}">적용됨</span></td>

View File

@@ -10,10 +10,10 @@
<details class="explanation-details">
<summary>도움말</summary>
<p>
<code>POC_2</code> KB 업무 테이블 table/column comment와 Oracle annotation을 조회·수정합니다.
<code th:text="${catalog.owner()}">OWNER</code>의 승인된 업무 테이블 table/column comment와 Oracle annotation을 조회·수정합니다.
Select AI profile의 <code>comments=true</code>, <code>annotations=true</code> 설정에서는 이 값들이 SQL 생성 근거로 들어갑니다.
</p>
<p class="mb-0">임의 스키마나 임의 테이블은 수정하지 않고, 백오피스가 승인한 7개 업무 테이블만 대상으로 합니다.</p>
<p class="mb-0">임의 스키마나 임의 테이블은 수정하지 않고, JSON 카탈로그가 승인한 업무 테이블만 대상으로 합니다.</p>
</details>
</section>
@@ -24,18 +24,18 @@
<div class="section-heading">
<div>
<h2>테이블 선택</h2>
<p class="section-subtitle">정형 MCP/Select AI가 참조하는 KB 업무 원장 7개만 표시합니다.</p>
<p class="section-subtitle" th:text="${catalog.catalogDescription()}">승인된 업무 원장만 표시합니다.</p>
</div>
<span class="badge text-bg-secondary" th:text="${#lists.size(tables)}">7</span>
<span class="badge text-bg-secondary" th:text="${#lists.size(tables)}">6</span>
</div>
<div class="structured-table-grid">
<a th:each="entry : ${tables}"
class="structured-table-card"
th:classappend="${entry.key() == selectedKey} ? ' is-selected'"
th:href="@{/schema-metadata(table=${entry.key()})}">
<strong th:text="${entry.businessName()}">고객원장</strong>
<code th:text="${entry.tableName()}">KB_CUSTOMERS</code>
<small th:text="${entry.description()}">고객 기본정보</small>
<strong th:text="${entry.businessName()}">직원 원장</strong>
<code th:text="${entry.tableName()}">HMM_HR_EMPLOYEES</code>
<small th:text="${entry.description()}">직원·조직 정보</small>
</a>
</div>
</section>
@@ -44,9 +44,9 @@
<div class="section-heading">
<div>
<span class="badge text-bg-secondary">TABLE</span>
<h2 class="mt-2" th:text="${metadata.table().businessName()}">계약원장</h2>
<h2 class="mt-2" th:text="${metadata.table().businessName()}">직원 원장</h2>
<p class="section-subtitle">
<code th:text="${'POC_2.' + metadata.table().tableName()}">POC_2.KB_CONTRACTS</code>
<code th:text="${catalog.owner() + '.' + metadata.table().tableName()}">OWNER.TABLE_NAME</code>
<span th:text="${' · ' + metadata.table().description()}"> · 설명</span>
</p>
</div>

View File

@@ -8,7 +8,8 @@
<h1>정형 데이터 조회</h1>
<details class="explanation-details">
<summary>도움말</summary>
<p>보험 원장 7개만 읽기 전용으로 조회합니다. 임의 SQL이나 수정 기능은 제공하지 않으며, 한 번에 최대 50건까지만 표시합니다.</p>
<p th:text="${catalog.pageHelp()}">승인된 업무 원장만 읽기 전용으로 조회합니다.</p>
<p class="mb-0" th:text="${'한 번에 최대 ' + catalog.rowLimit() + '건까지만 표시합니다.'}">한 번에 최대 50건까지만 표시합니다.</p>
</details>
</div>
@@ -20,7 +21,7 @@
<div class="section-heading">
<div>
<h2>조회할 원장 선택</h2>
<p class="section-subtitle">KBAIPOC의 <code>POC_2</code> 스키마에서 승인된 정형 테이블만 표시합니다.</p>
<p class="section-subtitle" th:text="${catalog.catalogDescription()}">승인된 정형 테이블만 표시합니다.</p>
</div>
</div>
<div class="structured-table-grid">
@@ -28,9 +29,9 @@
class="structured-table-card"
th:classappend="${entry.key() == selectedKey} ? ' is-selected'"
th:href="@{/structured-data(table=${entry.key()})}">
<strong th:text="${entry.businessName()}">고객원장</strong>
<code th:text="${entry.tableName()}">KB_CUSTOMERS</code>
<small th:text="${entry.description()}">고객 기본정보</small>
<strong th:text="${entry.businessName()}">직원 원장</strong>
<code th:text="${entry.tableName()}">HMM_HR_EMPLOYEES</code>
<small th:text="${entry.description()}">직원·조직 정보</small>
</a>
</div>
</section>
@@ -40,9 +41,9 @@
<section class="content-band" th:if="${preview}">
<div class="section-heading">
<div>
<h2 th:text="${preview.table().businessName()}">고객원장</h2>
<h2 th:text="${preview.table().businessName()}">직원 원장</h2>
<p class="section-subtitle">
<code th:text="${'POC_2.' + preview.table().tableName()}">POC_2.KB_CUSTOMERS</code>
<code th:text="${catalog.owner() + '.' + preview.table().tableName()}">OWNER.TABLE_NAME</code>
<span th:text="${' · 최대 ' + preview.rowLimit() + '건'}"> · 최대 50건</span>
</p>
</div>