첫 실측이 보인 원인은 축 예산의 합(245 vs 상한 100)이었다. 캡 없는 두 축만 캡하는 시뮬레이션(80/50, 60/40)으로는 20/20 이 그대로 100 이라 총합 기준으로 다시 짰다. 예산: 등록 권리 대상 일치 80(단독 high) · 웹 존재 40(검색결과 사본 유사도·Vision 매치· CSE 페이지가 제공자 무관 한 풀, 뷰 강도로만 40/30/10) · 인물 30/10 · 이름 있는 검색 승격 15 · 라벨 10 → 등록 제외 최대 95. 외부 검색 실패는 +30/행 가산 대신 medium 하한. 검색결과 사본 행은 knowledge_entry_id 부재 + url/source_evidence_ids 로 웹 풀에 간다. 격자 432: high 92→75%, 포화 80→44%(남은 포화는 전부 등록 강한 일치 조합), 웹 신호만 high 13/24→0/24. 실이미지 20장 리스코어: 100점 20→0, 구별 점수 1→4(75/80/92/95), 밴드는 전부 high 유지(전부 웹에 있는 인물 사진 — medium/low 임계는 여전히 미검증). 다이어그램 spec 3종 v5 + 재생성(archify 2.17). operator-review-workflow 는 새 desktop-readability 검사에 HEAD 그대로 걸려 노드 폭 132→124 로 통과시켰고, 그 확대로 1440x900 세로 13px 넘침이 남는다(visual-check containment) — INDEX 에 기록. verify.ps1: ruff clean, 654 passed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BStHFrjQj2VypecSG9ex1V
338 lines
7 KiB
JSON
338 lines
7 KiB
JSON
{
|
|
"schema_version": 1,
|
|
"diagram_type": "architecture",
|
|
"meta": {
|
|
"title": "POSA Copyrighter 시스템 구성",
|
|
"output": "docs/diagrams/system-architecture.html",
|
|
"quality_profile": "showcase",
|
|
"viewBox": [
|
|
1080,
|
|
500
|
|
],
|
|
"views": [
|
|
{
|
|
"id": "request-path",
|
|
"label": "요청 경로",
|
|
"focus": [
|
|
"console",
|
|
"http",
|
|
"store",
|
|
"sqlite"
|
|
],
|
|
"note": "정적 콘솔에서 스토어와 SQLite 까지 가는 주 경로."
|
|
},
|
|
{
|
|
"id": "analysis",
|
|
"label": "분석 · 채점",
|
|
"focus": [
|
|
"store",
|
|
"images",
|
|
"analysis"
|
|
],
|
|
"note": "제출 이미지에서 증거와 점수가 만들어지는 고리."
|
|
},
|
|
{
|
|
"id": "egress",
|
|
"label": "외부 경계",
|
|
"focus": [
|
|
"store",
|
|
"gate",
|
|
"fetch",
|
|
"providers",
|
|
"ollama"
|
|
],
|
|
"note": "폐쇄망을 넘는 유일한 경로와 그 앞의 두 관문."
|
|
}
|
|
]
|
|
},
|
|
"components": [
|
|
{
|
|
"id": "console",
|
|
"type": "frontend",
|
|
"label": "운영자 콘솔",
|
|
"sublabel": "정적 SPA · 빌드 없음",
|
|
"tag": "app-*.js 15",
|
|
"pos": [
|
|
36,
|
|
170
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "throttle",
|
|
"type": "security",
|
|
"label": "인증 스로틀",
|
|
"sublabel": "10회 / 60초",
|
|
"tag": "주소별",
|
|
"pos": [
|
|
250,
|
|
60
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "http",
|
|
"type": "backend",
|
|
"label": "http_app",
|
|
"sublabel": "라우팅 · 인증 · CSP",
|
|
"tag": "바디 10MB",
|
|
"pos": [
|
|
250,
|
|
170
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "images",
|
|
"type": "database",
|
|
"label": "이미지 저장소",
|
|
"sublabel": "제출물 · manifest",
|
|
"pos": [
|
|
464,
|
|
60
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "store",
|
|
"type": "backend",
|
|
"label": "CopyrighterStore",
|
|
"sublabel": "믹스인 8개 조립",
|
|
"tag": "판정 · 감사",
|
|
"pos": [
|
|
464,
|
|
170
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "sqlite",
|
|
"type": "database",
|
|
"label": "SQLite",
|
|
"sublabel": "payload JSON · WAL",
|
|
"tag": "SCHEMA v2",
|
|
"pos": [
|
|
464,
|
|
280
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "analysis",
|
|
"type": "backend",
|
|
"label": "분석 · 채점",
|
|
"sublabel": "지문 · 얼굴 · 출처",
|
|
"tag": "RiskScorer v5",
|
|
"pos": [
|
|
678,
|
|
60
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "gate",
|
|
"type": "security",
|
|
"label": "외부 호출 게이트",
|
|
"sublabel": "쿼터 · 비상 차단",
|
|
"pos": [
|
|
678,
|
|
280
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "ollama",
|
|
"type": "external",
|
|
"label": "로컬 LLM",
|
|
"sublabel": "ollama · qwen2.5:7b",
|
|
"tag": "선택",
|
|
"pos": [
|
|
892,
|
|
170
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "fetch",
|
|
"type": "security",
|
|
"label": "store_remote_fetch",
|
|
"sublabel": "SSRF 가드",
|
|
"tag": "DNS 1회 해석",
|
|
"pos": [
|
|
892,
|
|
280
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
},
|
|
{
|
|
"id": "providers",
|
|
"type": "external",
|
|
"label": "외부 검색 API",
|
|
"sublabel": "Vision · CSE · 네이버",
|
|
"pos": [
|
|
678,
|
|
420
|
|
],
|
|
"size": [
|
|
124,
|
|
62
|
|
]
|
|
}
|
|
],
|
|
"boundaries": [
|
|
{
|
|
"kind": "region",
|
|
"label": "폐쇄망 (air-gapped) — 런타임 서드파티는 이미지 처리 3종",
|
|
"wraps": [
|
|
"console",
|
|
"throttle",
|
|
"http",
|
|
"images",
|
|
"store",
|
|
"sqlite",
|
|
"analysis",
|
|
"gate",
|
|
"ollama",
|
|
"fetch"
|
|
]
|
|
},
|
|
{
|
|
"kind": "security-group",
|
|
"label": "네트워크 경계",
|
|
"wraps": [
|
|
"gate",
|
|
"fetch"
|
|
]
|
|
}
|
|
],
|
|
"connections": [
|
|
{
|
|
"id": "console-api",
|
|
"from": "console",
|
|
"to": "http",
|
|
"label": "REST",
|
|
"variant": "emphasis"
|
|
},
|
|
{
|
|
"id": "auth-throttle",
|
|
"from": "throttle",
|
|
"to": "http",
|
|
"label": "인증 시도 제한",
|
|
"variant": "security",
|
|
"labelDy": 24
|
|
},
|
|
{
|
|
"id": "http-store",
|
|
"from": "http",
|
|
"to": "store",
|
|
"variant": "emphasis"
|
|
},
|
|
{
|
|
"id": "store-sqlite",
|
|
"from": "store",
|
|
"to": "sqlite",
|
|
"label": "payload JSON",
|
|
"variant": "emphasis",
|
|
"labelDy": 24
|
|
},
|
|
{
|
|
"id": "store-images",
|
|
"from": "store",
|
|
"to": "images"
|
|
},
|
|
{
|
|
"id": "analysis-store",
|
|
"from": "analysis",
|
|
"to": "store",
|
|
"label": "증거 · 점수 · 밴드",
|
|
"labelDy": 24
|
|
},
|
|
{
|
|
"id": "store-gate",
|
|
"from": "store",
|
|
"to": "gate",
|
|
"label": "외부 호출 요청"
|
|
},
|
|
{
|
|
"id": "gate-fetch",
|
|
"from": "gate",
|
|
"to": "fetch",
|
|
"label": "허용 시 통과",
|
|
"variant": "security"
|
|
},
|
|
{
|
|
"id": "fetch-providers",
|
|
"from": "fetch",
|
|
"to": "providers",
|
|
"label": "HTTPS",
|
|
"variant": "security"
|
|
},
|
|
{
|
|
"id": "store-ollama",
|
|
"from": "store",
|
|
"to": "ollama",
|
|
"label": "판독 요청",
|
|
"variant": "dashed"
|
|
}
|
|
],
|
|
"cards": [
|
|
{
|
|
"dot": "rose",
|
|
"title": "경계",
|
|
"items": [
|
|
"설치·런타임에 인터넷 없음을 전제한다 — CDN · 원격 fetch · 자동업데이트 금지",
|
|
"외부로 나가는 경로는 store_remote_fetch 하나뿐이고 SSRF 가드가 앞에 있다",
|
|
"게이트는 쿼터와 비상 차단을 본다 — 시드 · 재분석 · 얼굴 크롭 경로 모두 통과한다"
|
|
]
|
|
},
|
|
{
|
|
"dot": "emerald",
|
|
"title": "서버",
|
|
"items": [
|
|
"http_app 이 라우팅 · Bearer/세션 인증 · CSP · CSRF · 10MB 바디 상한을 맡는다",
|
|
"CopyrighterStore 는 믹스인 8개로 조립되고 SQLite payload JSON 에 쓴다",
|
|
"BatchAnalyzer 를 스토어가 구동하고, 증거·점수·밴드가 스토어로 돌아온다"
|
|
]
|
|
},
|
|
{
|
|
"dot": "cyan",
|
|
"title": "콘솔 · 의존성",
|
|
"items": [
|
|
"콘솔은 빌드 스텝이 없는 클래식 스크립트 15개로 전역 스코프를 공유한다 — 로드 순서가 계약",
|
|
"얼굴 검출은 YuNet(ONNX)이고 가중치는 gitignore 된 models/ 에 있다",
|
|
"런타임 서드파티는 numpy · opencv-python-headless · pillow 3종",
|
|
"LLM 은 로컬 ollama 선택 사항이며 없으면 연결이 빠르게 실패한다"
|
|
]
|
|
}
|
|
]
|
|
}
|