94 lines
7.5 KiB
XML
94 lines
7.5 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1138" height="300" viewBox="0 0 1138 300" role="img" aria-labelledby="diagram-title diagram-description">
|
|
<title id="diagram-title">패턴 이동은 credential contract의 소유권 전환이다</title>
|
|
<desc id="diagram-description">네 항목을 호출 계약, 소유권, 브라우저 계약, 운영 책임, 전환 성격의 다섯 축으로 비교한다. AP1에서 AP2는 Resource Server의 Bearer 계약을 유지하면서 OAuth callback을 mediator로 옮긴다. AP2에서 AP3는 browser의 access endpoint와 direct API 호출을 없애고 UI API를 BFF 계약으로 바꾼다. AP3에서 AP4는 application-owned session과 orchestration을 edge-owned session과 identity projection으로 전환한다. AP4에서 AP3로 되돌아가는 선택도 별도 항목으로 두어 번호 순서나 성숙도 상승을 암시하지 않는다.</desc>
|
|
<metadata>{"techviz":{"spec_version":"1.1","id":"credential-contract-migration","profile":"comparison"},"source_context":{"document":"document.md","document_sha256":"df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371","anchor":{"kind":"marker","value":"credential-contract-migration","line":1293}},"evidence_policy":"Each factual element cites source lines or is marked assumption.","diagram_only":true}</metadata>
|
|
<defs>
|
|
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" />
|
|
</marker>
|
|
<style>
|
|
:root { color-scheme: light; }
|
|
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
|
.canvas { fill: #ffffff; }
|
|
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
|
|
.group-label-bg { fill: #ffffff; }
|
|
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
|
|
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
|
|
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
|
|
.edge.style-dotted { stroke-dasharray: 2 5; }
|
|
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.edge.emphasis-muted { stroke: #9ca3af; }
|
|
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
|
|
.edge-label-bg { fill: #ffffff; }
|
|
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
|
|
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
|
|
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
|
|
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
|
|
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
|
|
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
|
|
.node-shape.assumption { stroke-dasharray: 4 4; }
|
|
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
|
|
.controller-led { fill: #4b5563; }
|
|
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
|
|
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
|
|
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
|
|
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
|
|
.node-detail { font-size: 11px; fill: #374151; }
|
|
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
|
|
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
|
|
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
|
|
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
|
|
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
|
|
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
|
|
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
|
|
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
|
|
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
|
|
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
|
|
</style>
|
|
</defs>
|
|
<rect class="canvas" width="1138" height="300" />
|
|
<g id="node-ap1-to-ap2">
|
|
<rect class="node-shape kind-concept emphasis-normal role-contract" data-evidence="1285-1285" x="45.0" y="45.0" width="223.0" height="139.0" rx="7" />
|
|
<text class="node-label" x="156.5" y="72.5">AP1 → AP2</text>
|
|
<line class="node-detail-divider" x1="59.0" y1="93.5" x2="254.0" y2="93.5" />
|
|
<text class="node-detail" x="61.0" y="110.5">호출 · Bearer API 유지</text>
|
|
<text class="node-detail" x="61.0" y="126.5">소유 · callback → mediator</text>
|
|
<text class="node-detail" x="61.0" y="142.5">브라우저 · access API + session</text>
|
|
<text class="node-detail" x="61.0" y="158.5">운영 · CORS → AP2 UI</text>
|
|
<text class="node-detail" x="61.0" y="174.5">성격 · callback 재배치</text>
|
|
</g>
|
|
<g id="node-ap2-to-ap3">
|
|
<rect class="node-shape kind-concept emphasis-normal role-contract" data-evidence="1287-1287" x="320.0" y="45.0" width="223.0" height="139.0" rx="7" />
|
|
<text class="node-label" x="431.5" y="72.5">AP2 → AP3</text>
|
|
<line class="node-detail-divider" x1="334.0" y1="93.5" x2="529.0" y2="93.5" />
|
|
<text class="node-detail" x="336.0" y="110.5">호출 · direct API → /bff/**</text>
|
|
<text class="node-detail" x="336.0" y="126.5">소유 · UI API → BFF</text>
|
|
<text class="node-detail" x="336.0" y="142.5">브라우저 · /token/access 제거</text>
|
|
<text class="node-detail" x="336.0" y="158.5">운영 · error mapping + CSRF</text>
|
|
<text class="node-detail" x="336.0" y="174.5">성격 · direct path 제거</text>
|
|
</g>
|
|
<g id="node-ap3-to-ap4">
|
|
<rect class="node-shape kind-concept emphasis-normal role-contract" data-evidence="1289-1289" x="595.0" y="45.0" width="223.0" height="139.0" rx="7" />
|
|
<text class="node-label" x="706.5" y="72.5">AP3 → AP4</text>
|
|
<line class="node-detail-divider" x1="609.0" y1="93.5" x2="804.0" y2="93.5" />
|
|
<text class="node-detail" x="611.0" y="110.5">호출 · API 조합 → identity</text>
|
|
<text class="node-detail" x="611.0" y="126.5">소유 · app session → edge</text>
|
|
<text class="node-detail" x="611.0" y="142.5">브라우저 · identity projection</text>
|
|
<text class="node-detail" x="611.0" y="158.5">운영 · 인가 → upstream/policy</text>
|
|
<text class="node-detail" x="611.0" y="174.5">성격 · upgrade 아님</text>
|
|
</g>
|
|
<g id="node-ap4-to-ap3">
|
|
<rect class="node-shape kind-concept emphasis-normal role-contract" data-evidence="1291-1291" x="870.0" y="45.0" width="223.0" height="139.0" rx="7" />
|
|
<text class="node-label" x="981.5" y="72.5">AP4 → AP3</text>
|
|
<line class="node-detail-divider" x1="884.0" y1="93.5" x2="1079.0" y2="93.5" />
|
|
<text class="node-detail" x="886.0" y="110.5">호출 · headers → BFF workflow</text>
|
|
<text class="node-detail" x="886.0" y="126.5">소유 · claims/workflow → BFF</text>
|
|
<text class="node-detail" x="886.0" y="142.5">브라우저 · app workflow</text>
|
|
<text class="node-detail" x="886.0" y="158.5">운영 · state + verification</text>
|
|
<text class="node-detail" x="886.0" y="174.5">성격 · 역방향 가능</text>
|
|
</g>
|
|
</svg>
|