POSA_Copyrighter/web/operator-gui/pitch-assets/risk-pipeline.svg
유창욱 3f7b3a9cf2 chore: initial commit of copyrighter (rights_filter)
Image rights / copyright detection system: SQLite store, HTTP app,
search integrations (Naver, Google Custom Search, Google Cloud Vision
web detection), image analysis (fingerprints, face/person detection,
evidence enrichment, risk scoring), an admin/review layer, governance
and retention policies, batch jobs, and a browser-based operator GUI.

This baseline incorporates a full code-review remediation pass
(46 fixes; 358 tests passing). Highlights:

CRITICAL
- Prevent evidence cascade-delete during the schema-constraint
  migration by disabling FK enforcement around the table rebuild.

Security
- Sandbox served media (neutralize stored XSS from uploaded/collected
  SVGs) via CSP + nosniff on the untrusted media routes.
- Strip embedded EXIF/GPS from external image derivatives before they
  are sent to third-party APIs.
- Return a clean 404 (not an uncaught StopIteration) for PATCH on an
  unknown provider.

Correctness
- LLM-summary failures no longer add +30 to the risk score.
- Decode only explicit JS escapes so Korean image URLs are not mangled.
- Consume search quota only after a successful request.
- Naver/Google adapters map responses inside the failure boundary, so a
  malformed response degrades to evidence instead of crashing enrichment.
- Domain-aware provider attribution; face-box IoU de-duplication; count
  searches (not result items); per-box crop isolation; clamp evidence
  confidence and Google CSE num; real submittedEpoch; and more.

Robustness
- Offline LLM connect fast-fails (short connect timeout) so seed/reload
  requests are not stalled; full read timeout preserved for generation.
- Malformed numeric env vars fall back to defaults instead of crashing
  startup.

Performance
- Per-submission evidence reads (no full-table scan per rescore),
  audit-log LIMIT, lazy active-store lookup, hoisted timestamps.

Tests
- ~24 regression tests added pinning the above fixes.

Runtime data (data/, outputs/, *.sqlite3, *.log), secrets (.env), and
node_modules are gitignored.
2026-06-09 09:50:31 +09:00

62 lines
4.2 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="560" viewBox="0 0 1280 560" role="img" aria-labelledby="risk-title risk-desc">
<title id="risk-title">Copyrighter 저작권 위험 판별 파이프라인</title>
<desc id="risk-desc">제출 이미지가 로컬 분석, 이미지 지문, 얼굴 인물 감지, Google 웹 탐지, Naver 검색, 기준 DB와 주의 후보 유사도, 증거 보드, 위험 점수, 운영자 판정으로 이어지는 흐름</desc>
<defs>
<marker id="risk-arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#2f6272"/>
</marker>
<style>
.label{font-family:"Segoe UI","Malgun Gothic",sans-serif;font-size:22px;font-weight:800;fill:#172124}
.small{font-family:"Segoe UI","Malgun Gothic",sans-serif;font-size:15px;font-weight:700;fill:#4a5558}
.node{fill:#fff;stroke:#8aa0a6;stroke-width:2}
.node-key{fill:#fff7df;stroke:#d6a33a;stroke-width:2}
.node-good{fill:#ecf8f0;stroke:#2f6d50;stroke-width:2}
.node-risk{fill:#fff0ed;stroke:#a63f35;stroke-width:2}
.edge{fill:none;stroke:#2f6272;stroke-width:3;marker-end:url(#risk-arrow)}
</style>
</defs>
<rect width="1280" height="560" fill="#f8f5ef"/>
<text x="44" y="44" class="small">Mermaid flowchart · risk-pipeline</text>
<rect x="52" y="222" width="160" height="82" rx="14" class="node"/>
<text x="132" y="257" text-anchor="middle" class="label">제출</text>
<text x="132" y="284" text-anchor="middle" class="label">이미지</text>
<path d="M212 263 L282 263" class="edge"/>
<rect x="282" y="222" width="160" height="82" rx="14" class="node"/>
<text x="362" y="257" text-anchor="middle" class="label">로컬</text>
<text x="362" y="284" text-anchor="middle" class="label">분석</text>
<path d="M442 263 L500 263 L500 105 L550 105" class="edge"/>
<path d="M442 263 L500 263 L500 210 L550 210" class="edge"/>
<path d="M442 263 L500 263 L500 315 L550 315" class="edge"/>
<path d="M442 263 L500 263 L500 420 L550 420" class="edge"/>
<rect x="550" y="64" width="178" height="82" rx="14" class="node"/>
<text x="639" y="100" text-anchor="middle" class="label">이미지</text>
<text x="639" y="126" text-anchor="middle" class="label">지문</text>
<rect x="550" y="169" width="178" height="82" rx="14" class="node"/>
<text x="639" y="204" text-anchor="middle" class="label">얼굴/인물</text>
<text x="639" y="231" text-anchor="middle" class="label">감지</text>
<rect x="550" y="274" width="178" height="82" rx="14" class="node"/>
<text x="639" y="310" text-anchor="middle" class="label">Google</text>
<text x="639" y="337" text-anchor="middle" class="label">웹 탐지</text>
<rect x="550" y="379" width="178" height="82" rx="14" class="node"/>
<text x="639" y="414" text-anchor="middle" class="label">Naver</text>
<text x="639" y="441" text-anchor="middle" class="label">텍스트 검색</text>
<path d="M728 105 L800 105" class="edge"/>
<rect x="800" y="64" width="178" height="82" rx="14" class="node-key"/>
<text x="889" y="99" text-anchor="middle" class="label">기준 DB</text>
<text x="889" y="126" text-anchor="middle" class="label">주의 후보</text>
<path d="M728 210 L760 210 L760 270 L806 270" class="edge"/>
<path d="M728 315 L760 315 L760 270 L806 270" class="edge"/>
<path d="M728 420 L760 420 L760 270 L806 270" class="edge"/>
<path d="M978 105 L1014 105 L1014 270 L1040 270" class="edge"/>
<rect x="806" y="224" width="180" height="92" rx="14" class="node"/>
<text x="896" y="258" text-anchor="middle" class="label">증거 보드</text>
<text x="896" y="286" text-anchor="middle" class="small">출처 · 이미지 · 상태</text>
<path d="M986 270 L1040 270" class="edge"/>
<rect x="1040" y="224" width="126" height="92" rx="14" class="node-good"/>
<text x="1103" y="258" text-anchor="middle" class="label">위험</text>
<text x="1103" y="286" text-anchor="middle" class="label">점수</text>
<path d="M1166 270 L1204 270" class="edge"/>
<rect x="1204" y="224" width="56" height="92" rx="14" class="node-risk"/>
<text x="1232" y="255" text-anchor="middle" class="small">운영자</text>
<text x="1232" y="281" text-anchor="middle" class="small">판정</text>
</svg>