Consolidate data access control backoffice updates
This commit is contained in:
198
src/main/resources/templates/schema-metadata.html
Normal file
198
src/main/resources/templates/schema-metadata.html
Normal file
@@ -0,0 +1,198 @@
|
||||
<!doctype html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="~{fragments/layout :: head('DB 메타데이터')}"></head>
|
||||
<body>
|
||||
<nav th:replace="~{fragments/layout :: nav}"></nav>
|
||||
<main class="container py-4">
|
||||
<section class="page-title">
|
||||
<span class="badge text-bg-primary">Select AI 근거 메타데이터</span>
|
||||
<h1 class="mt-2">DB 메타데이터</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>
|
||||
<code>POC_2</code> KB 업무 테이블의 table/column comment와 Oracle annotation을 조회·수정합니다.
|
||||
Select AI profile의 <code>comments=true</code>, <code>annotations=true</code> 설정에서는 이 값들이 SQL 생성 근거로 들어갑니다.
|
||||
</p>
|
||||
<p class="mb-0">임의 스키마나 임의 테이블은 수정하지 않고, 백오피스가 승인한 7개 업무 테이블만 대상으로 합니다.</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section class="alert alert-success" th:if="${message}" th:text="${message}">저장 완료</section>
|
||||
<section class="alert alert-danger" th:if="${errorMessage}" th:text="${errorMessage}">오류</section>
|
||||
|
||||
<section class="content-band">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>테이블 선택</h2>
|
||||
<p class="section-subtitle">정형 MCP/Select AI가 참조하는 KB 업무 원장 7개만 표시합니다.</p>
|
||||
</div>
|
||||
<span class="badge text-bg-secondary" th:text="${#lists.size(tables)}">7</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>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="content-band" th:if="${metadata}">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="badge text-bg-secondary">TABLE</span>
|
||||
<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>
|
||||
<span th:text="${' · ' + metadata.table().description()}"> · 설명</span>
|
||||
</p>
|
||||
</div>
|
||||
<a class="btn btn-sm rw-btn-secondary" th:href="@{/structured-data(table=${metadata.table().key()})}">데이터 미리보기</a>
|
||||
</div>
|
||||
|
||||
<form method="post" action="/schema-metadata/table-comment" class="mb-4">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<label class="form-label fw-semibold">Table comment</label>
|
||||
<textarea class="form-control" rows="3" name="comment" maxlength="4000"
|
||||
th:text="${metadata.tableComment()}"></textarea>
|
||||
<div class="form-hint mt-1">Oracle <code>COMMENT ON TABLE</code>로 즉시 반영됩니다. 빈 값으로 저장하면 comment를 비웁니다.</div>
|
||||
<button class="btn rw-btn-primary mt-2" type="submit">테이블 comment 저장</button>
|
||||
</form>
|
||||
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h3>Table annotations</h3>
|
||||
<p class="section-subtitle">기존 annotation은 값 수정 또는 빈 값 저장으로 삭제할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle">
|
||||
<thead><tr><th style="width: 220px;">Annotation</th><th>Value</th><th style="width: 110px;"></th></tr></thead>
|
||||
<tbody>
|
||||
<tr th:each="annotation : ${metadata.tableAnnotations()}">
|
||||
<td><code th:text="${annotation.name()}">DISPLAY_NAME</code></td>
|
||||
<td>
|
||||
<form method="post" action="/schema-metadata/table-annotation" class="metadata-inline-form">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<input type="hidden" name="annotationName" th:value="${annotation.name()}">
|
||||
<textarea class="form-control" rows="2" name="annotationValue" maxlength="4000"
|
||||
th:text="${annotation.value()}"></textarea>
|
||||
<div class="form-hint mt-1">저장 전 기존 같은 key는 DROP 후 다시 ADD합니다.</div>
|
||||
<button class="btn btn-sm rw-btn-primary mt-2" type="submit">저장</button>
|
||||
</form>
|
||||
</td>
|
||||
<td class="text-muted">기존</td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(metadata.tableAnnotations())}">
|
||||
<td colspan="3" class="text-muted">등록된 table annotation이 없습니다.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<form method="post" action="/schema-metadata/table-annotation" class="row g-2 align-items-start">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<div class="col-md-3">
|
||||
<input class="form-control" name="annotationName" placeholder="예: QUERY_HINT" maxlength="128">
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<textarea class="form-control" rows="2" name="annotationValue" maxlength="4000"
|
||||
placeholder="Select AI가 참고할 업무 의미, 조인 힌트, 값 도메인 등을 입력"></textarea>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn rw-btn-secondary w-100" type="submit">추가</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="content-band" th:if="${metadata}">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>Column comments / annotations</h2>
|
||||
<p class="section-subtitle">컬럼 comment와 컬럼 annotation을 수정합니다. 저장 즉시 DB dictionary에 반영됩니다.</p>
|
||||
</div>
|
||||
<span class="badge text-bg-secondary" th:text="${#lists.size(metadata.columns()) + '개 컬럼'}">0개 컬럼</span>
|
||||
</div>
|
||||
|
||||
<div class="metadata-column-stack">
|
||||
<details class="content-band nested-content-band"
|
||||
th:each="column : ${metadata.columns()}"
|
||||
th:open="${!#lists.isEmpty(column.annotations())}">
|
||||
<summary class="d-flex justify-content-between align-items-center gap-3">
|
||||
<span>
|
||||
<code th:text="${column.columnName()}">CONTRACT_NO</code>
|
||||
<small class="text-muted ms-2" th:text="${column.dataType()}">VARCHAR2(30)</small>
|
||||
<span class="badge text-bg-light ms-2" th:text="${column.nullable()} ? 'NULL 허용' : 'NOT NULL'">NOT NULL</span>
|
||||
</span>
|
||||
<span class="text-muted" th:text="${#lists.size(column.annotations()) + ' annotations'}">0 annotations</span>
|
||||
</summary>
|
||||
|
||||
<form method="post" action="/schema-metadata/column-comment" class="mt-3">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<input type="hidden" name="column" th:value="${column.columnName()}">
|
||||
<label class="form-label fw-semibold">Column comment</label>
|
||||
<textarea class="form-control" rows="2" name="comment" maxlength="4000"
|
||||
th:text="${column.comment()}"></textarea>
|
||||
<button class="btn btn-sm rw-btn-primary mt-2" type="submit">컬럼 comment 저장</button>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive mt-3">
|
||||
<table class="table table-sm align-middle">
|
||||
<thead><tr><th style="width: 220px;">Annotation</th><th>Value</th><th style="width: 110px;"></th></tr></thead>
|
||||
<tbody>
|
||||
<tr th:each="annotation : ${column.annotations()}">
|
||||
<td><code th:text="${annotation.name()}">DISPLAY_NAME</code></td>
|
||||
<td>
|
||||
<form method="post" action="/schema-metadata/column-annotation">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<input type="hidden" name="column" th:value="${column.columnName()}">
|
||||
<input type="hidden" name="annotationName" th:value="${annotation.name()}">
|
||||
<textarea class="form-control" rows="2" name="annotationValue" maxlength="4000"
|
||||
th:text="${annotation.value()}"></textarea>
|
||||
<button class="btn btn-sm rw-btn-primary mt-2" type="submit">저장</button>
|
||||
</form>
|
||||
</td>
|
||||
<td class="text-muted">기존</td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(column.annotations())}">
|
||||
<td colspan="3" class="text-muted">등록된 column annotation이 없습니다.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<form method="post" action="/schema-metadata/column-annotation" class="row g-2 align-items-start">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="table" th:value="${metadata.table().key()}">
|
||||
<input type="hidden" name="column" th:value="${column.columnName()}">
|
||||
<div class="col-md-3">
|
||||
<input class="form-control" name="annotationName" placeholder="예: VALUE_DOMAIN" maxlength="128">
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<textarea class="form-control" rows="2" name="annotationValue" maxlength="4000"
|
||||
placeholder="컬럼 표시명, 값 범위, 조인 대상, 민감도 등을 입력"></textarea>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn rw-btn-secondary w-100" type="submit">추가</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user