POSA_Copyrighter/web/operator-gui/index.html

499 lines
25 KiB
HTML

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>권리 검수 콘솔</title>
<link rel="preload" href="assets/fonts/PretendardVariable.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="styles.css">
<script src="operator-labels.js" defer></script>
<script src="submission-import.js" defer></script>
<script src="evidence-guidance.js" defer></script>
<script src="operator-search.js" defer></script>
<script src="app.js" defer></script>
</head>
<body data-internal-only="true">
<div class="app-shell">
<nav class="nav-rail" aria-label="내부 운영 콘솔">
<div class="brand-block">
<span class="brand-mark" aria-hidden="true">CR</span>
<div>
<strong>권리 검수기</strong>
<span>권리 심사 콘솔</span>
</div>
</div>
<button class="nav-button active" type="button" data-view="queue" aria-current="page">
<span aria-hidden="true">Q</span>
<span>심사 큐</span>
</button>
<button class="nav-button" type="button" data-view="workbench">
<span aria-hidden="true">C</span>
<span>케이스 심사</span>
</button>
<button class="nav-button" type="button" data-view="knowledge">
<span aria-hidden="true">K</span>
<span>기준 DB</span>
</button>
<button class="nav-button" type="button" data-view="providers">
<span aria-hidden="true">P</span>
<span>외부 검색 tool 활용</span>
</button>
<button class="nav-button" type="button" data-view="audit">
<span aria-hidden="true">A</span>
<span>감사 로그</span>
</button>
<div class="nav-footer">
<span class="status-dot ok" aria-hidden="true"></span>
<span>내부 전용</span>
</div>
</nav>
<div class="workspace">
<header class="top-bar">
<div class="product-purpose" aria-label="제품 목적">
<strong>이미지 저작권 위험 심사</strong>
<span>제출 이미지, 외부 검색 근거, 내부 기준 DB를 한 화면에서 검토합니다.</span>
</div>
<div class="queue-health" id="queue-health" aria-live="polite"></div>
<div class="provider-pulse" id="provider-pulse" aria-label="외부 검색 tool 활용 상태"></div>
<div class="coverage-tabs" id="coverage-tabs" aria-label="검색 근거 필터" aria-live="polite"></div>
</header>
<main class="main-surface" id="app-main">
<section class="view active" id="queue-view" data-view-panel="queue" aria-labelledby="queue-title">
<div class="section-header">
<div>
<p class="eyebrow">심사 대기열</p>
<h1 id="queue-title">권리 위험 심사 큐</h1>
<p class="queue-intent" id="queue-upload-guidance">사진을 추가하면 현재 큐에 새 심사 건으로 들어가고, 바로 케이스 심사 화면에서 확인할 수 있습니다.</p>
</div>
<div class="queue-actions">
<label class="queue-folder-input" for="submission-folder">
<span>제출 폴더</span>
<input id="submission-folder" type="text" placeholder="비워두면 현재 큐 재확인">
</label>
<label class="queue-file-input" for="submission-image">
<span>사진 추가</span>
<span id="submission-image-name">선택된 파일 없음</span>
<input id="submission-image" type="file" accept="image/*">
</label>
<button class="secondary-action" type="button" id="upload-submission-image">사진 넣기</button>
<button class="primary-action" type="button" id="reload-submissions">새 제출 불러오기</button>
<button class="secondary-action" type="button" id="bulk-rerun">선택 재분석</button>
</div>
</div>
<div class="import-status" id="submission-import-status" aria-live="polite"></div>
<section class="operator-workflow" aria-label="운영 흐름">
<article>
<span>1</span>
<strong>심사 건 추가</strong>
<p>사진 추가 또는 제출 폴더 불러오기로 검토할 이미지를 큐에 올립니다.</p>
</article>
<article>
<span>2</span>
<strong>근거 보강</strong>
<p>근거 부족 사유와 추천 쿼리로 외부 검색 결과를 보강합니다.</p>
</article>
<article>
<span>3</span>
<strong>운영 결정</strong>
<p>승인·보류·반려 결정을 남기고 필요한 경우 기준 DB에 반영합니다.</p>
</article>
</section>
<div class="toolbar" aria-label="큐 필터">
<div class="segmented" id="risk-filter" aria-label="위험도">
<button class="active" type="button" data-risk="all">전체</button>
<button type="button" data-risk="high">높음</button>
<button type="button" data-risk="medium">중간</button>
<button type="button" data-risk="low">낮음</button>
<button type="button" data-risk="failed">실패</button>
<button type="button" data-risk="pending">대기</button>
</div>
<label>
<span>증거 출처</span>
<select id="source-filter">
<option value="all">전체</option>
<option value="naver">네이버 근거</option>
<option value="google">구글 근거</option>
<option value="fingerprint">이미지 유사도</option>
<option value="face">얼굴/인물 감지</option>
<option value="llm">내부 요약</option>
<option value="failure">외부 검색 tool 실패</option>
</select>
</label>
<label>
<span>결정 상태</span>
<select id="decision-filter">
<option value="all">전체</option>
<option value="unreviewed">미심사</option>
<option value="held">보류</option>
<option value="rejected">반려</option>
<option value="approved">승인</option>
<option value="corrected">보정됨</option>
</select>
</label>
<label>
<span>정렬</span>
<select id="queue-sort">
<option value="risk">위험도순</option>
<option value="newest">최신순</option>
<option value="oldest">오래된순</option>
<option value="analysis_failure">분석 실패</option>
<option value="provider_failure">외부 검색 tool 실패</option>
</select>
</label>
<label class="filter-search">
<span>큐 검색</span>
<input id="queue-search" type="search" autocomplete="off" placeholder="SUB-1002, 아이돌, toon...">
</label>
</div>
<div class="table-shell queue-grid-shell">
<table class="queue-table queue-grid">
<thead>
<tr>
<th scope="col"><span class="sr-only">선택</span></th>
<th scope="col">이미지</th>
<th scope="col">제출</th>
<th scope="col">위험</th>
<th scope="col">상위 근거</th>
<th scope="col">외부 검색 tool 활용</th>
<th scope="col">지원자 상태</th>
<th scope="col">운영 결정</th>
<th scope="col">시간</th>
</tr>
</thead>
<tbody id="queue-body"></tbody>
</table>
</div>
</section>
<section class="view" id="workbench-view" data-view-panel="workbench" aria-labelledby="case-title" hidden>
<div class="section-header">
<div>
<p class="eyebrow">케이스 심사</p>
<h1 id="case-title">케이스 심사</h1>
</div>
<div class="case-actions">
<button class="secondary-action" type="button" id="rerun-enrichment">증거 재수집</button>
<button class="secondary-action" type="button" id="open-correction">보정 열기</button>
</div>
</div>
<div class="workbench-tabs" role="tablist" aria-label="케이스 워크벤치">
<button class="active" type="button" data-workbench-tab="evidence">근거 및 판단</button>
<button type="button" data-workbench-tab="queries">검색 이력</button>
</div>
<section class="workbench-panel active" data-workbench-panel="evidence">
<div class="case-layout evidence-layout">
<aside class="pane decision-pane floating-decision-panel" aria-labelledby="decision-pane-title">
<div class="pane-heading floating-decision-head">
<div>
<p class="eyebrow">운영자 판정</p>
<h2 id="decision-pane-title">판정</h2>
</div>
<span class="score-pill risk-pending" id="floating-case-score">대기</span>
</div>
<div class="recommendation-box" id="recommendation-box"></div>
<label class="memo-field" for="decision-memo">
<span>결정 메모</span>
<textarea id="decision-memo" rows="3" placeholder="반려 또는 보정 시 메모 필수"></textarea>
</label>
<p class="form-error" id="memo-error" aria-live="assertive"></p>
<div class="decision-actions">
<button class="approve-action" type="button" data-decision="approved">승인</button>
<button class="hold-action" type="button" data-decision="held">보류</button>
<button class="reject-action" type="button" data-decision="rejected" data-requires-memo="true">반려</button>
</div>
<details class="decision-secondary">
<summary>보조 작업</summary>
<div class="derived-preview" id="derived-preview"></div>
<div class="quick-actions">
<button type="button" id="add-from-case">주의 후보 보기</button>
<button type="button" id="mark-irrelevant">증거 미사용 처리</button>
<button type="button" id="disable-derived">자동 항목 비활성</button>
</div>
</details>
</aside>
<section class="pane image-pane" aria-labelledby="image-pane-title">
<div class="pane-heading">
<h2 id="image-pane-title">제출 이미지</h2>
<div class="icon-actions" aria-label="이미지 보기 제어">
<button type="button" id="fit-image" title="맞춤">맞춤</button>
<button type="button" id="actual-image" title="실제 크기">1:1</button>
<button type="button" id="rotate-image" title="회전">회전</button>
</div>
</div>
<figure class="review-image-frame">
<img id="case-image" src="assets/case-portrait.svg" alt="심사 대상 제출 이미지">
<figcaption id="image-derivative-note"></figcaption>
</figure>
<div class="fact-grid" id="file-facts"></div>
<div class="similar-strip" id="similar-strip" aria-label="유사 이미지"></div>
<div class="similar-strip face-crop-strip" id="face-crop-strip" aria-label="감지된 얼굴 영역"></div>
</section>
<section class="pane evidence-pane" aria-labelledby="evidence-pane-title">
<div class="pane-heading">
<h2 id="evidence-pane-title">증거와 판단 근거</h2>
<span class="score-pill" id="case-score"></span>
</div>
<div id="rerun-diff-summary" class="rerun-diff-summary"></div>
<div id="case-reasons" class="reason-list"></div>
<div id="evidence-next-actions" class="evidence-next-actions"></div>
<div id="evidence-groups" class="evidence-groups"></div>
</section>
</div>
</section>
<section class="workbench-panel" data-workbench-panel="queries" aria-labelledby="evidence-title" hidden>
<div class="section-header">
<div>
<p class="eyebrow">근거 검색</p>
<h1 id="evidence-title">검색 증거 재현</h1>
</div>
</div>
<div class="split-workspace">
<section class="pane">
<div class="pane-heading">
<h2>쿼리 기록</h2>
<span id="query-case-label"></span>
</div>
<div id="query-history" class="stack-list"></div>
</section>
<section class="pane">
<div class="pane-heading">
<h2>수동 텍스트 쿼리</h2>
</div>
<form id="manual-query-form" class="manual-query-form">
<label for="manual-query-provider">
<span>외부 검색 tool 활용</span>
<select id="manual-query-provider">
<option value="naver">네이버 검색</option>
</select>
</label>
<label for="manual-query">
<span>쿼리</span>
<input id="manual-query" type="text" autocomplete="off" placeholder="작품명, 인물명, 키워드">
</label>
<button class="primary-action" type="submit">실행</button>
</form>
<div id="manual-query-status" class="inline-status" aria-live="polite"></div>
<div id="search-results" class="stack-list"></div>
</section>
</div>
</section>
</section>
<section class="view" id="knowledge-view" data-view-panel="knowledge" aria-labelledby="knowledge-title" hidden>
<div class="section-header">
<div>
<p class="eyebrow">기준 데이터베이스</p>
<h1 id="knowledge-title">기준 데이터베이스</h1>
</div>
</div>
<div class="knowledge-tabs" role="tablist" aria-label="기준 데이터베이스">
<button class="active" type="button" data-knowledge-tab="collect">후보 수집</button>
<button type="button" data-knowledge-tab="registered">등록된 기준</button>
<button type="button" data-knowledge-tab="manual">수동 등록</button>
<button type="button" data-knowledge-tab="corrections">보정 기록</button>
</div>
<section class="knowledge-panel active" data-knowledge-panel="collect">
<section class="pane">
<div class="pane-heading">
<h2>키워드 후보 수집</h2>
</div>
<form id="candidate-collection-form" class="candidate-collection-form">
<label for="collection-provider">
<span>외부 검색 tool 활용</span>
<select id="collection-provider">
<option value="naver">네이버 검색</option>
</select>
</label>
<label for="collection-query">
<span>키워드</span>
<input id="collection-query" type="text" autocomplete="off" placeholder="인물명, 그룹명, 작품명">
</label>
<button class="primary-action" type="submit">후보 수집</button>
</form>
<div id="collection-status" class="inline-status" aria-live="polite"></div>
<div class="candidate-selection-actions">
<button class="secondary-action" type="button" id="select-all-candidates">전체 선택</button>
<button class="secondary-action" type="button" id="clear-selected-candidates">전체 선택 취소</button>
</div>
<div id="collection-candidates" class="collection-candidates"></div>
</section>
</section>
<section class="knowledge-panel" data-knowledge-panel="registered" hidden>
<section class="pane">
<div class="pane-heading">
<h2>등록된 기준</h2>
</div>
<div class="knowledge-filter-bar">
<label for="knowledge-search">
<span>검색</span>
<input id="knowledge-search" type="search" autocomplete="off" placeholder="이름, 별칭, 키워드">
</label>
<label for="knowledge-type-filter">
<span>유형</span>
<select id="knowledge-type-filter">
<option value="all">전체</option>
<option value="public_figure">연예인/유명인</option>
<option value="work">작품</option>
<option value="character">캐릭터</option>
<option value="game">게임</option>
<option value="rejected_image">반려 이미지</option>
</select>
</label>
<label for="knowledge-status-filter">
<span>상태</span>
<select id="knowledge-status-filter">
<option value="all">전체</option>
<option value="confirmed">확정 DB</option>
<option value="watchlist">주의 후보</option>
<option value="excluded">제외됨</option>
</select>
</label>
<label for="knowledge-active-filter">
<span>활성</span>
<select id="knowledge-active-filter">
<option value="all">전체</option>
<option value="active">활성</option>
<option value="inactive">비활성</option>
</select>
</label>
</div>
<div id="knowledge-list" class="stack-list"></div>
</section>
</section>
<section class="knowledge-panel" data-knowledge-panel="manual" hidden>
<section class="pane">
<div class="pane-heading compact-heading">
<h2>선택 후보 묶어서 편입</h2>
</div>
<form id="collection-promotion-form" class="collection-promotion-form">
<label>
<span>편입 이름</span>
<input id="collection-promotion-name" type="text" autocomplete="off" placeholder="인물명, 작품명, 캐릭터명">
</label>
<label>
<span>유형</span>
<select id="collection-promotion-type">
<option value="public_figure">연예인/유명인</option>
<option value="work">작품</option>
<option value="character">캐릭터</option>
<option value="game">게임</option>
<option value="rejected_reference">반려 이미지 참조</option>
</select>
</label>
<label>
<span>별칭</span>
<input id="collection-promotion-aliases" type="text" autocomplete="off" placeholder="쉼표로 구분">
</label>
<label>
<span>검색 키워드</span>
<input id="collection-promotion-keywords" type="text" autocomplete="off" placeholder="쉼표로 구분">
</label>
<label class="wide-field">
<span>판단 메모</span>
<textarea id="collection-promotion-memo" rows="3" placeholder="후보를 같은 대상의 샘플로 묶은 이유"></textarea>
</label>
<button class="primary-action" type="submit" id="promote-selected-candidates">선택 후보 묶어서 편입</button>
</form>
<div class="section-divider" aria-hidden="true"></div>
<div class="pane-heading">
<h2>수동 기준 등록</h2>
</div>
<form id="knowledge-form" class="knowledge-form">
<label>
<span>이름</span>
<input id="knowledge-name" type="text" autocomplete="off" required>
</label>
<label>
<span>유형</span>
<select id="knowledge-type">
<option value="public_figure">연예인/유명인</option>
<option value="work">작품</option>
<option value="character">캐릭터</option>
<option value="game">게임</option>
<option value="rejected_reference">반려 이미지 참조</option>
</select>
</label>
<label>
<span>별칭</span>
<input id="knowledge-aliases" type="text" autocomplete="off" placeholder="쉼표로 구분">
</label>
<label>
<span>검색 키워드</span>
<input id="knowledge-keywords" type="text" autocomplete="off" placeholder="쉼표로 구분">
</label>
<label class="file-picker" for="knowledge-image">
<span>참조 이미지</span>
<span class="file-picker-control">
<span class="file-picker-button">이미지 선택</span>
<span id="knowledge-image-name">선택된 파일 없음</span>
</span>
<input id="knowledge-image" class="file-picker-input" type="file" accept="image/*">
</label>
<label>
<span>정책 메모</span>
<textarea id="knowledge-memo" rows="5" required></textarea>
</label>
<button class="primary-action" type="submit">등록</button>
</form>
<div id="knowledge-entry-status" class="inline-status" aria-live="polite"></div>
</section>
</section>
<section class="knowledge-panel" data-knowledge-panel="corrections" hidden>
<div class="pane">
<div class="pane-heading">
<h2>오판 보정 기록</h2>
</div>
<div id="corrections-list" class="stack-list"></div>
</div>
</section>
</section>
<section class="view" id="providers-view" data-view-panel="providers" aria-labelledby="providers-title" hidden>
<div class="section-header">
<div>
<p class="eyebrow">외부 검색 tool 활용</p>
<h1 id="providers-title">외부 검색 tool 활용</h1>
</div>
<button class="danger-outline" type="button" id="emergency-disable">외부 검색 tool 즉시 중지</button>
</div>
<div id="providers-list" class="provider-list"></div>
</section>
<section class="view" id="audit-view" data-view-panel="audit" aria-labelledby="audit-title" hidden>
<div class="section-header">
<div>
<p class="eyebrow">감사 로그</p>
<h1 id="audit-title">감사 로그</h1>
</div>
</div>
<div class="table-shell">
<table class="audit-table">
<thead>
<tr>
<th scope="col">시간</th>
<th scope="col">행위자</th>
<th scope="col">이벤트</th>
<th scope="col">대상</th>
<th scope="col">변경</th>
</tr>
</thead>
<tbody id="audit-body"></tbody>
</table>
</div>
</section>
</main>
</div>
</div>
</body>
</html>