docs(keycloak-session-store): take the sentences out of the diagram canvases
The skill says drawings carry names and sentences go in <desc> and the paragraph beside the figure. I put sentences in node details and edge labels instead, and 27 of the 28 diagrams shipped with prose inside the canvas — "예측 다섯 개가 틀렸다", "아홉 번 조용히 실패했다", "막혀서 닿지 않는다". Only label and details render on the canvas; description does not. So every sentence moved to a noun phrase and the meaning stays in description, which was already carrying it. 막혀서 닿지 않는다 -> 차단 아홉 번 조용히 실패했다 -> 조용한 실패 9건 예측 다섯 개가 틀렸다 -> 틀린 예측 5건 로그아웃이 정리하지 않는다 -> 로그아웃 미정리 볼륨이 없으면 여기까지다 -> 볼륨 없음 Three node labels were sentences too and became names: 세션 스냅샷, 예측 선기록, 대조군 확보. What stays is what the rules protect — identifiers, commands and measured values: PRIMARY KEY (client_registration_id, principal_name), ValidationFailedException: 1 changesets check sum, nginx -t && nginx -s reload, SET LOCAL synchronous_commit TO OFF. Those are names of things, not prose about them. 294 canvas strings across 28 diagrams, none matching a sentence ending, average 11 characters. All 28 still lint clean and re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@@ -18,5 +18,5 @@
|
||||
## Relationships
|
||||
|
||||
- **keycloak-0 → TCP 7800:** 무효화 통지. Evidence: L186–L190.
|
||||
- **keycloak-1 → PostgreSQL:** 세션은 여기서 읽는다 — 7800 과 무관. Evidence: L186–L189.
|
||||
- **TCP 7800 → keycloak-1:** 막혀서 닿지 않는다. Evidence: L186–L190.
|
||||
- **keycloak-1 → PostgreSQL:** 세션 SELECT. Evidence: L186–L189.
|
||||
- **TCP 7800 → keycloak-1:** 차단. Evidence: L186–L190.
|
||||
|
||||
@@ -14,5 +14,5 @@ n3: "PostgreSQL" {
|
||||
shape: cylinder
|
||||
}
|
||||
n0 -> n1: "무효화 통지"
|
||||
n1 -> n2: "막혀서 닿지 않는다"
|
||||
n2 -> n3: "세션은 여기서 읽는다 — 7800 과 무관"
|
||||
n1 -> n2: "차단"
|
||||
n2 -> n3: "세션 SELECT"
|
||||
|
||||
@@ -7,6 +7,6 @@ digraph techviz {
|
||||
n2 [label="keycloak-1", shape=box, style="rounded,filled"];
|
||||
n3 [label="PostgreSQL", shape=cylinder, style="rounded,filled"];
|
||||
n0 -> n1 [label="무효화 통지", style=solid];
|
||||
n1 -> n2 [label="막혀서 닿지 않는다", style=solid];
|
||||
n2 -> n3 [label="세션은 여기서 읽는다 — 7800 과 무관", style=solid];
|
||||
n1 -> n2 [label="차단", style=solid];
|
||||
n2 -> n3 [label="세션 SELECT", style=solid];
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_k0" value="keycloak-0" tooltip="로그아웃을 처리한 노드. | Evidence: L183-L189" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="92.5" y="60.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="82.0" y="60.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_transport" value="TCP 7800<br/>8080·9000 만 열고 누락시킨다" tooltip="무효화 통지가 지나는 길. NetworkPolicy 로 막았다. | Evidence: L191-L196" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="80.5" y="220.0" width="174.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_transport" value="TCP 7800<br/>허용 포트 8080 · 9000" tooltip="무효화 통지가 지나는 길. NetworkPolicy 로 막았다. | Evidence: L191-L196" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="80.5" y="220.0" width="153.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_k1" value="keycloak-1<br/>400 이어야 할 refresh 가 200" tooltip="통지를 못 받아 세션이 죽은 것을 모른다. | Evidence: L183-L189" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="387.0" width="195.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_k1" value="keycloak-1<br/>refresh 200 (기대 400)" tooltip="통지를 못 받아 세션이 죽은 것을 모른다. | Evidence: L183-L189" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="387.0" width="174.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_db" value="PostgreSQL<br/>교차 노드 refresh 200" tooltip="세션이 여기 있어 7800 과 무관하다. | Evidence: L186-L190" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="91.0" y="554.0" width="153.0" height="97.0" as="geometry"/>
|
||||
<mxGeometry x="80.5" y="554.0" width="153.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_k0-t" value="무효화 통지" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_k0" target="n_transport">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="191.5" y="172.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="172.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_k1-db" value="세션은 여기서 읽는다 — 7800 과 무관" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_k1" target="n_db">
|
||||
<mxCell id="e_k1-db" value="세션 SELECT" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_k1" target="n_db">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="191.5" y="506.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="506.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_t-k1" value="막혀서 닿지 않는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_transport" target="n_k1">
|
||||
<mxCell id="e_t-k1" value="차단" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_transport" target="n_k1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="191.5" y="339.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="339.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"id": "edge-k0-t",
|
||||
"type": "arrow",
|
||||
"x": 167.5,
|
||||
"x": 157.0,
|
||||
"y": 124.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -66,7 +66,7 @@
|
||||
{
|
||||
"id": "edge-label-k0-t",
|
||||
"type": "text",
|
||||
"x": 146.5,
|
||||
"x": 136.0,
|
||||
"y": 160.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -105,7 +105,7 @@
|
||||
{
|
||||
"id": "edge-k1-db",
|
||||
"type": "arrow",
|
||||
"x": 167.5,
|
||||
"x": 157.0,
|
||||
"y": 458.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -165,9 +165,9 @@
|
||||
{
|
||||
"id": "edge-label-k1-db",
|
||||
"type": "text",
|
||||
"x": 99.5,
|
||||
"x": 136.0,
|
||||
"y": 494.0,
|
||||
"width": 184,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -193,18 +193,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "세션은 여기서 읽는다 — 7800 과 무관",
|
||||
"text": "세션 SELECT",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "세션은 여기서 읽는다 — 7800 과 무관",
|
||||
"originalText": "세션 SELECT",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-t-k1",
|
||||
"type": "arrow",
|
||||
"x": 167.5,
|
||||
"x": 157.0,
|
||||
"y": 291.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -264,7 +264,7 @@
|
||||
{
|
||||
"id": "edge-label-t-k1",
|
||||
"type": "text",
|
||||
"x": 146.5,
|
||||
"x": 136.0,
|
||||
"y": 327.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -292,18 +292,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "막혀서 닿지 않는다",
|
||||
"text": "차단",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "막혀서 닿지 않는다",
|
||||
"originalText": "차단",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-k0",
|
||||
"type": "rectangle",
|
||||
"x": 92.5,
|
||||
"x": 82.0,
|
||||
"y": 60.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
@@ -333,7 +333,7 @@
|
||||
{
|
||||
"id": "node-label-k0",
|
||||
"type": "text",
|
||||
"x": 102.5,
|
||||
"x": 92.0,
|
||||
"y": 70.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
@@ -374,7 +374,7 @@
|
||||
"type": "rectangle",
|
||||
"x": 80.5,
|
||||
"y": 220.0,
|
||||
"width": 174.0,
|
||||
"width": 153.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -404,7 +404,7 @@
|
||||
"type": "text",
|
||||
"x": 90.5,
|
||||
"y": 230.0,
|
||||
"width": 154.0,
|
||||
"width": 133.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -430,11 +430,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "TCP 7800\n8080·9000 만 열고 누락시킨다",
|
||||
"text": "TCP 7800\n허용 포트 8080 · 9000",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "TCP 7800\n8080·9000 만 열고 누락시킨다",
|
||||
"originalText": "TCP 7800\n허용 포트 8080 · 9000",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -443,7 +443,7 @@
|
||||
"type": "rectangle",
|
||||
"x": 70.0,
|
||||
"y": 387.0,
|
||||
"width": 195.0,
|
||||
"width": 174.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -473,7 +473,7 @@
|
||||
"type": "text",
|
||||
"x": 80.0,
|
||||
"y": 397.0,
|
||||
"width": 175.0,
|
||||
"width": 154.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -499,18 +499,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "keycloak-1\n400 이어야 할 refresh 가 200",
|
||||
"text": "keycloak-1\nrefresh 200 (기대 400)",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "keycloak-1\n400 이어야 할 refresh 가 200",
|
||||
"originalText": "keycloak-1\nrefresh 200 (기대 400)",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-db",
|
||||
"type": "rectangle",
|
||||
"x": 91.0,
|
||||
"x": 80.5,
|
||||
"y": 554.0,
|
||||
"width": 153.0,
|
||||
"height": 97.0,
|
||||
@@ -540,7 +540,7 @@
|
||||
{
|
||||
"id": "node-label-db",
|
||||
"type": "text",
|
||||
"x": 101.0,
|
||||
"x": 90.5,
|
||||
"y": 564.0,
|
||||
"width": 133.0,
|
||||
"height": 77.0,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a1-transport-vs-discovery",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "af42cd905290687548b620849f1e143752f9ab346de4de352701256cc6657e32",
|
||||
"spec_sha256": "f54cae81276a31a8b73961148cadf3ae5cd256bdc38a9c002997fce63c243ebf",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -6,5 +6,5 @@ flowchart TB
|
||||
n2["keycloak-1"]
|
||||
n3[("PostgreSQL")]
|
||||
n0 -->|"무효화 통지"| n1
|
||||
n1 -->|"막혀서 닿지 않는다"| n2
|
||||
n2 -->|"세션은 여기서 읽는다 — 7800 과 무관"| n3
|
||||
n1 -->|"차단"| n2
|
||||
n2 -->|"세션 SELECT"| n3
|
||||
|
||||
@@ -50,35 +50,35 @@
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="696" />
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="167.5,124.0 167.5,172.0 167.5,172.0 167.5,220.0" data-evidence="186-190" />
|
||||
<rect class="edge-label-bg" x="162.4" y="158.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="173.0">무효화 통지</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="167.5,458.0 167.5,506.0 167.5,506.0 167.5,554.0" data-evidence="186-189" />
|
||||
<rect class="edge-label-bg" x="105.5" y="492.0" width="172.1" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="507.0">세션은 여기서 읽는다 — 7800 과 무관</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="167.5,291.0 167.5,339.0 167.5,339.0 167.5,387.0" data-evidence="186-190" />
|
||||
<rect class="edge-label-bg" x="149.0" y="325.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="340.0">막혀서 닿지 않는다</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="157.0,124.0 157.0,172.0 157.0,172.0 157.0,220.0" data-evidence="186-190" />
|
||||
<rect class="edge-label-bg" x="151.9" y="158.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="173.0">무효화 통지</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="157.0,458.0 157.0,506.0 157.0,506.0 157.0,554.0" data-evidence="186-189" />
|
||||
<rect class="edge-label-bg" x="141.8" y="492.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="507.0">세션 SELECT</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="157.0,291.0 157.0,339.0 157.0,339.0 157.0,387.0" data-evidence="186-190" />
|
||||
<rect class="edge-label-bg" x="159.0" y="325.0" width="44.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="340.0">차단</text>
|
||||
<g id="node-k0">
|
||||
<rect class="node-shape kind-service emphasis-primary role-source" data-evidence="183-189" x="92.5" y="60.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="167.5" y="90.0">keycloak-0</text>
|
||||
<rect class="node-shape kind-service emphasis-primary role-source" data-evidence="183-189" x="82.0" y="60.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="90.0">keycloak-0</text>
|
||||
</g>
|
||||
<g id="node-transport">
|
||||
<rect class="node-shape kind-channel emphasis-warning role-control" data-evidence="191-196" x="80.5" y="220.0" width="174.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="167.5" y="247.0">TCP 7800</text>
|
||||
<line class="node-detail-divider" x1="94.5" y1="268.0" x2="240.5" y2="268.0" />
|
||||
<text class="node-detail" x="96.5" y="285.0">8080·9000 만 열고 누락시킨다</text>
|
||||
<rect class="node-shape kind-channel emphasis-warning role-control" data-evidence="191-196" x="80.5" y="220.0" width="153.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="247.0">TCP 7800</text>
|
||||
<line class="node-detail-divider" x1="94.5" y1="268.0" x2="219.5" y2="268.0" />
|
||||
<text class="node-detail" x="96.5" y="285.0">허용 포트 8080 · 9000</text>
|
||||
</g>
|
||||
<g id="node-k1">
|
||||
<rect class="node-shape kind-service emphasis-primary role-target" data-evidence="183-189" x="70.0" y="387.0" width="195.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="167.5" y="414.0">keycloak-1</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="435.0" x2="251.0" y2="435.0" />
|
||||
<text class="node-detail" x="86.0" y="452.0">400 이어야 할 refresh 가 200</text>
|
||||
<rect class="node-shape kind-service emphasis-primary role-target" data-evidence="183-189" x="70.0" y="387.0" width="174.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="414.0">keycloak-1</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="435.0" x2="230.0" y2="435.0" />
|
||||
<text class="node-detail" x="86.0" y="452.0">refresh 200 (기대 400)</text>
|
||||
</g>
|
||||
<g id="node-db">
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-store" data-evidence="186-190" x="91.0" y="567.0" width="153.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-store" cx="167.5" cy="567.0" rx="76.5" ry="13.0" /><path class="storage-bottom" d="M 91.0 638.0 A 76.5 13.0 0 0 0 244.0 638.0" />
|
||||
<text class="node-label" x="167.5" y="594.0">PostgreSQL</text>
|
||||
<line class="node-detail-divider" x1="105.0" y1="615.0" x2="230.0" y2="615.0" />
|
||||
<text class="node-detail" x="107.0" y="632.0">교차 노드 refresh 200</text>
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-store" data-evidence="186-190" x="80.5" y="567.0" width="153.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-store" cx="157.0" cy="567.0" rx="76.5" ry="13.0" /><path class="storage-bottom" d="M 80.5 638.0 A 76.5 13.0 0 0 0 233.5 638.0" />
|
||||
<text class="node-label" x="157.0" y="594.0">PostgreSQL</text>
|
||||
<line class="node-detail-divider" x1="94.5" y1="615.0" x2="219.5" y2="615.0" />
|
||||
<text class="node-detail" x="96.5" y="632.0">교차 노드 refresh 200</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
@@ -5,7 +5,7 @@
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_client" value="클라이언트<br/>로그인 153건 성공" tooltip="200 과 토큰을 받는다. | Evidence: L207-L213" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_client" value="클라이언트<br/>성공 응답 153건" tooltip="200 과 토큰을 받는다. | Evidence: L207-L213" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="134.5" y="60.0" width="150.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_keycloak" value="Keycloak<br/>SET LOCAL synchronous_commit TO OFF" tooltip="트랜잭션마다 synchronous_commit 을 끈다. | Evidence: L211-L215" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
@@ -14,7 +14,7 @@
|
||||
<mxCell id="n_pg" value="PostgreSQL<br/>wal_writer_delay 200ms" tooltip="COMMIT 을 즉시 반환한다. WAL 은 아직 메모리에 있다. | Evidence: L211-L215" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="115.5" y="407.0" width="188.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_disk" value="디스크의 WAL<br/>DB 에 실제로 존재 149건" tooltip="여기 닿아야 살아남는다. | Evidence: L207-L215" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_disk" value="디스크의 WAL<br/>DB 존재 149건" tooltip="여기 닿아야 살아남는다. | Evidence: L207-L215" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="134.5" y="600.0" width="150.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_c-k" value="로그인 요청" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client" target="n_keycloak">
|
||||
|
||||
@@ -361,11 +361,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "클라이언트\n로그인 153건 성공",
|
||||
"text": "클라이언트\n성공 응답 153건",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "클라이언트\n로그인 153건 성공",
|
||||
"originalText": "클라이언트\n성공 응답 153건",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "디스크의 WAL\nDB 에 실제로 존재 149건",
|
||||
"text": "디스크의 WAL\nDB 존재 149건",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "디스크의 WAL\nDB 에 실제로 존재 149건",
|
||||
"originalText": "디스크의 WAL\nDB 존재 149건",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a3-commit-to-disk-gap",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "29e279f39e07ba519e4e0685e5719d5d63b3ecf8b61a18816cbd5a1529baf854",
|
||||
"spec_sha256": "1dfb52c8df3953df103ea2d515cf5a4f3cfed507d286e093fad31b583a851ce2",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -79,6 +79,6 @@
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-target" data-evidence="207-215" x="134.5" y="613.0" width="150.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-target" cx="209.5" cy="613.0" rx="75.0" ry="13.0" /><path class="storage-bottom" d="M 134.5 684.0 A 75.0 13.0 0 0 0 284.5 684.0" />
|
||||
<text class="node-label" x="209.5" y="640.0">디스크의 WAL</text>
|
||||
<line class="node-detail-divider" x1="148.5" y1="661.0" x2="270.5" y2="661.0" />
|
||||
<text class="node-detail" x="150.5" y="678.0">DB 에 실제로 존재 149건</text>
|
||||
<text class="node-detail" x="150.5" y="678.0">DB 존재 149건</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
@@ -8,13 +8,13 @@
|
||||
<mxCell id="n_client" value="외부 요청" tooltip="사용자. | Evidence: L221-L228" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="92.5" y="60.0" width="150.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_entry" value="진입 경로 (kc-lab-1)<br/>kubectl 도 불통" tooltip="traefik 과 API 서버. 잃으면 000 이다. | Evidence: L221-L231" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rhombus;perimeter=rhombusPerimeter;fillColor=#fff7e8;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxCell id="n_entry" value="진입 경로 (kc-lab-1)<br/>kubectl 불통" tooltip="traefik 과 API 서버. 잃으면 000 이다. | Evidence: L221-L231" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rhombus;perimeter=rhombusPerimeter;fillColor=#fff7e8;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="92.5" y="240.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_workload" value="keycloak-0 (kc-lab-2)<br/>도달할 수 없을 뿐이다" tooltip="4b 에서는 계속 돌고 있었다. | Evidence: L221-L231" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxCell id="n_workload" value="keycloak-0 (kc-lab-2)<br/>도달 불가" tooltip="4b 에서는 계속 돌고 있었다. | Evidence: L221-L231" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="77.0" y="407.0" width="181.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_store" value="PostgreSQL (kc-lab-2)<br/>local-path PVC 라 재배치 불가" tooltip="4a 에서 함께 죽는다. 잃으면 503 이다. | Evidence: L221-L233" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxCell id="n_store" value="PostgreSQL (kc-lab-2)<br/>local-path PVC · 재배치 불가" tooltip="4a 에서 함께 죽는다. 잃으면 503 이다. | Evidence: L221-L233" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="574.0" width="195.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_c-e" value="요청" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client" target="n_entry">
|
||||
|
||||
@@ -430,11 +430,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "진입 경로 (kc-lab-1)\nkubectl 도 불통",
|
||||
"text": "진입 경로 (kc-lab-1)\nkubectl 불통",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "진입 경로 (kc-lab-1)\nkubectl 도 불통",
|
||||
"originalText": "진입 경로 (kc-lab-1)\nkubectl 불통",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -499,11 +499,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "keycloak-0 (kc-lab-2)\n도달할 수 없을 뿐이다",
|
||||
"text": "keycloak-0 (kc-lab-2)\n도달 불가",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "keycloak-0 (kc-lab-2)\n도달할 수 없을 뿐이다",
|
||||
"originalText": "keycloak-0 (kc-lab-2)\n도달 불가",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "PostgreSQL (kc-lab-2)\nlocal-path PVC 라 재배치 불가",
|
||||
"text": "PostgreSQL (kc-lab-2)\nlocal-path PVC · 재배치 불가",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "PostgreSQL (kc-lab-2)\nlocal-path PVC 라 재배치 불가",
|
||||
"originalText": "PostgreSQL (kc-lab-2)\nlocal-path PVC · 재배치 불가",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a4-two-node-losses",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "788cb5ef3210d1bb16d41feb27bd35f4041e93fea3e9826e4463391b82ccee5e",
|
||||
"spec_sha256": "3c9bc2fcbc853f176e8a38fc838062a36779083d1affe8e46a560484e230233b",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -67,18 +67,18 @@
|
||||
<polygon class="node-shape kind-gateway emphasis-warning role-control" data-evidence="221-231" points="167.5,240.0 242.5,275.5 167.5,311.0 92.5,275.5" />
|
||||
<text class="node-label" x="167.5" y="267.0">진입 경로 (kc-lab-1)</text>
|
||||
<line class="node-detail-divider" x1="106.5" y1="288.0" x2="228.5" y2="288.0" />
|
||||
<text class="node-detail" x="108.5" y="305.0">kubectl 도 불통</text>
|
||||
<text class="node-detail" x="108.5" y="305.0">kubectl 불통</text>
|
||||
</g>
|
||||
<g id="node-workload">
|
||||
<rect class="node-shape kind-service emphasis-normal role-control" data-evidence="221-231" x="77.0" y="407.0" width="181.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="167.5" y="434.0">keycloak-0 (kc-lab-2)</text>
|
||||
<line class="node-detail-divider" x1="91.0" y1="455.0" x2="244.0" y2="455.0" />
|
||||
<text class="node-detail" x="93.0" y="472.0">도달할 수 없을 뿐이다</text>
|
||||
<text class="node-detail" x="93.0" y="472.0">도달 불가</text>
|
||||
</g>
|
||||
<g id="node-store">
|
||||
<rect class="node-shape kind-datastore emphasis-warning role-target" data-evidence="221-233" x="70.0" y="587.0" width="195.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-warning role-target" cx="167.5" cy="587.0" rx="97.5" ry="13.0" /><path class="storage-bottom" d="M 70.0 658.0 A 97.5 13.0 0 0 0 265.0 658.0" />
|
||||
<text class="node-label" x="167.5" y="614.0">PostgreSQL (kc-lab-2)</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="635.0" x2="251.0" y2="635.0" />
|
||||
<text class="node-detail" x="86.0" y="652.0">local-path PVC 라 재배치 불가</text>
|
||||
<text class="node-detail" x="86.0" y="652.0">local-path PVC · 재배치 불가</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -17,6 +17,6 @@ JGroups 는 한 방향이 막혀도 열린 방향으로 재연결한다. 그래
|
||||
|
||||
## Relationships
|
||||
|
||||
- **막은 방향 → keycloak-1:** 막혀서 닿지 않는다. Evidence: L226–L232.
|
||||
- **막은 방향 → keycloak-1:** 차단. Evidence: L226–L232.
|
||||
- **keycloak-0 → 막은 방향:** JGroups 메시지. Evidence: L226–L232.
|
||||
- **keycloak-1 → 열린 반대 방향:** 반대 방향으로 재연결. Evidence: L226–L232.
|
||||
|
||||
@@ -14,5 +14,5 @@ n3: "열린 반대 방향" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "JGroups 메시지"
|
||||
n1 -> n2: "막혀서 닿지 않는다"
|
||||
n1 -> n2: "차단"
|
||||
n2 -> n3: "반대 방향으로 재연결"
|
||||
|
||||
@@ -7,6 +7,6 @@ digraph techviz {
|
||||
n2 [label="keycloak-1", shape=box, style="rounded,filled"];
|
||||
n3 [label="열린 반대 방향", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="JGroups 메시지", style=solid];
|
||||
n1 -> n2 [label="막혀서 닿지 않는다", style=solid];
|
||||
n1 -> n2 [label="차단", style=solid];
|
||||
n2 -> n3 [label="반대 방향으로 재연결", style=solid];
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
<mxCell id="n_k1" value="keycloak-1<br/>readiness 실패" tooltip="분단되면 스스로 로드밸런서에서 빠진다. | Evidence: L226-L236" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="394.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_rev" value="열린 반대 방향<br/>가르지 못한다" tooltip="비대칭 차단에서는 여기로 재연결한다. | Evidence: L226-L232" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxCell id="n_rev" value="열린 반대 방향<br/>재연결 경로" tooltip="비대칭 차단에서는 여기로 재연결한다. | Evidence: L226-L232" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="561.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_f-k1" value="막혀서 닿지 않는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_fwd" target="n_k1">
|
||||
<mxCell id="e_f-k1" value="차단" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_fwd" target="n_k1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="169.0" y="346.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "막혀서 닿지 않는다",
|
||||
"text": "차단",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "막혀서 닿지 않는다",
|
||||
"originalText": "차단",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "열린 반대 방향\n가르지 못한다",
|
||||
"text": "열린 반대 방향\n재연결 경로",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "열린 반대 방향\n가르지 못한다",
|
||||
"originalText": "열린 반대 방향\n재연결 경로",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a5-partition-asymmetry",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "26b2dc620b94c979befdef3808475899361f52b7f622fc06a78b5c6c59cd72a7",
|
||||
"spec_sha256": "9b10dfa9cfb1f24e5b105da13bc8fde85130cc1cca2ddad54cd57c32bc2dfcf5",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -6,5 +6,5 @@ flowchart TB
|
||||
n2["keycloak-1"]
|
||||
n3["열린 반대 방향"]
|
||||
n0 -->|"JGroups 메시지"| n1
|
||||
n1 -->|"막혀서 닿지 않는다"| n2
|
||||
n1 -->|"차단"| n2
|
||||
n2 -->|"반대 방향으로 재연결"| n3
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="677" />
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="145.0,298.0 145.0,346.0 145.0,346.0 145.0,394.0" data-evidence="226-232" />
|
||||
<rect class="edge-label-bg" x="126.5" y="332.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="169.0" y="347.0">막혀서 닿지 않는다</text>
|
||||
<rect class="edge-label-bg" x="147.0" y="332.0" width="44.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="169.0" y="347.0">차단</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="145.0,131.0 145.0,179.0 145.0,179.0 145.0,227.0" data-evidence="226-232" />
|
||||
<rect class="edge-label-bg" x="123.2" y="165.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="169.0" y="180.0">JGroups 메시지</text>
|
||||
@@ -81,6 +81,6 @@
|
||||
<rect class="node-shape kind-channel emphasis-normal role-support" data-evidence="226-232" x="70.0" y="561.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="145.0" y="588.0">열린 반대 방향</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="609.0" x2="206.0" y2="609.0" />
|
||||
<text class="node-detail" x="86.0" y="626.0">가르지 못한다</text>
|
||||
<text class="node-detail" x="86.0" y="626.0">재연결 경로</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
@@ -17,6 +17,6 @@
|
||||
|
||||
## Relationships
|
||||
|
||||
- **주입한 지연 → 왕복 횟수만큼 누적:** 왕복마다 더해진다. Evidence: L253–L263.
|
||||
- **주입한 지연 → 왕복 횟수만큼 누적:** 왕복당 누적. Evidence: L253–L263.
|
||||
- **커넥션 풀 대기 → readiness 실패:** 프로브도 타임아웃. Evidence: L264–L273.
|
||||
- **왕복 횟수만큼 누적 → 커넥션 풀 대기:** 커넥션 점유가 길어진다. Evidence: L259–L268.
|
||||
- **왕복 횟수만큼 누적 → 커넥션 풀 대기:** 커넥션 점유. Evidence: L259–L268.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "커넥션 풀 대기" {
|
||||
n3: "readiness 실패" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "왕복마다 더해진다"
|
||||
n1 -> n2: "커넥션 점유가 길어진다"
|
||||
n0 -> n1: "왕복당 누적"
|
||||
n1 -> n2: "커넥션 점유"
|
||||
n2 -> n3: "프로브도 타임아웃"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="왕복 횟수만큼 누적", shape=box, style="rounded,filled"];
|
||||
n2 [label="커넥션 풀 대기", shape=box, style="rounded,filled"];
|
||||
n3 [label="readiness 실패", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="왕복마다 더해진다", style=solid];
|
||||
n1 -> n2 [label="커넥션 점유가 길어진다", style=solid];
|
||||
n0 -> n1 [label="왕복당 누적", style=solid];
|
||||
n1 -> n2 [label="커넥션 점유", style=solid];
|
||||
n2 -> n3 [label="프로브도 타임아웃", style=solid];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<mxCell id="n_probe" value="readiness 실패<br/>동시 20건 최대 22.2초" tooltip="느린 노드가 로드밸런서에서 빠진다. | Evidence: L269-L273" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="71.5" y="561.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_i-r" value="왕복마다 더해진다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_inject" target="n_roundtrips">
|
||||
<mxCell id="e_i-r" value="왕복당 누적" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_inject" target="n_roundtrips">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170.5" y="179.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
@@ -27,7 +27,7 @@
|
||||
<mxPoint x="170.5" y="513.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_r-p" value="커넥션 점유가 길어진다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_roundtrips" target="n_pool">
|
||||
<mxCell id="e_r-p" value="커넥션 점유" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_roundtrips" target="n_pool">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170.5" y="346.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "왕복마다 더해진다",
|
||||
"text": "왕복당 누적",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "왕복마다 더해진다",
|
||||
"originalText": "왕복당 누적",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -264,9 +264,9 @@
|
||||
{
|
||||
"id": "edge-label-r-p",
|
||||
"type": "text",
|
||||
"x": 122.5,
|
||||
"x": 125.5,
|
||||
"y": 334.0,
|
||||
"width": 96,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "커넥션 점유가 길어진다",
|
||||
"text": "커넥션 점유",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "커넥션 점유가 길어진다",
|
||||
"originalText": "커넥션 점유",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a6-latency-multiplication",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "c9d669f597dc9b26d68636bb52e7239c266a8c5985c73d51c3fe0b7ebd7ff231",
|
||||
"spec_sha256": "0b2994cb0a306f6fc1bd7fb2dae907ed79b6fe0bb6e908dba8509b0db1ca9f2b",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,6 +5,6 @@ flowchart TB
|
||||
n1["왕복 횟수만큼 누적"]
|
||||
n2["커넥션 풀 대기"]
|
||||
n3["readiness 실패"]
|
||||
n0 -->|"왕복마다 더해진다"| n1
|
||||
n1 -->|"커넥션 점유가 길어진다"| n2
|
||||
n0 -->|"왕복당 누적"| n1
|
||||
n1 -->|"커넥션 점유"| n2
|
||||
n2 -->|"프로브도 타임아웃"| n3
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="677" />
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="146.5,131.0 146.5,179.0 146.5,179.0 146.5,227.0" data-evidence="253-263" />
|
||||
<rect class="edge-label-bg" x="131.3" y="165.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="170.5" y="180.0">왕복마다 더해진다</text>
|
||||
<rect class="edge-label-bg" x="141.4" y="165.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="170.5" y="180.0">왕복당 누적</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="146.5,465.0 146.5,513.0 146.5,513.0 146.5,561.0" data-evidence="264-273" />
|
||||
<rect class="edge-label-bg" x="131.3" y="499.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="170.5" y="514.0">프로브도 타임아웃</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="146.5,298.0 146.5,346.0 146.5,346.0 146.5,394.0" data-evidence="259-268" />
|
||||
<rect class="edge-label-bg" x="121.3" y="332.0" width="98.4" height="22" rx="3" />
|
||||
<text class="edge-label" x="170.5" y="347.0">커넥션 점유가 길어진다</text>
|
||||
<rect class="edge-label-bg" x="141.4" y="332.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="170.5" y="347.0">커넥션 점유</text>
|
||||
<g id="node-inject">
|
||||
<rect class="node-shape kind-process emphasis-warning role-source" data-evidence="253-258" x="71.5" y="60.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="146.5" y="87.0">주입한 지연</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
@@ -17,6 +17,6 @@
|
||||
|
||||
## Relationships
|
||||
|
||||
- **PostgreSQL 세션 행 → 재시작 전 발급한 refresh token:** 세션이 남아 있어 통한다. Evidence: L270–L278.
|
||||
- **롤링 재시작 → Infinispan sessions 캐시:** 비운다. Evidence: L270–L278.
|
||||
- **롤링 재시작 → PostgreSQL 세션 행:** 건드리지 않는다. Evidence: L270–L278.
|
||||
- **PostgreSQL 세션 행 → 재시작 전 발급한 refresh token:** 세션 조회. Evidence: L270–L278.
|
||||
- **롤링 재시작 → Infinispan sessions 캐시:** 캐시 초기화. Evidence: L270–L278.
|
||||
- **롤링 재시작 → PostgreSQL 세션 행:** 변경 없음. Evidence: L270–L278.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "PostgreSQL 세션 행" {
|
||||
n3: "재시작 전 발급한 refresh token" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "비운다"
|
||||
n0 -> n2: "건드리지 않는다"
|
||||
n2 -> n3: "세션이 남아 있어 통한다"
|
||||
n0 -> n1: "캐시 초기화"
|
||||
n0 -> n2: "변경 없음"
|
||||
n2 -> n3: "세션 조회"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="Infinispan sessions 캐시", shape=box, style="rounded,filled"];
|
||||
n2 [label="PostgreSQL 세션 행", shape=cylinder, style="rounded,filled"];
|
||||
n3 [label="재시작 전 발급한 refresh token", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="비운다", style=solid];
|
||||
n0 -> n2 [label="건드리지 않는다", style=solid];
|
||||
n2 -> n3 [label="세션이 남아 있어 통한다", style=solid];
|
||||
n0 -> n1 [label="캐시 초기화", style=solid];
|
||||
n0 -> n2 [label="변경 없음", style=solid];
|
||||
n2 -> n3 [label="세션 조회", style=solid];
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
<mxCell id="n_refresh" value="재시작 전 발급한 refresh token<br/>200" tooltip="여전히 통한다. | Evidence: L270-L278" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="192.5" y="420.0" width="153.0" height="91.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_db-rt" value="세션이 남아 있어 통한다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_db" target="n_refresh">
|
||||
<mxCell id="e_db-rt" value="세션 조회" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_db" target="n_refresh">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="331.0" y="344.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_r-c" value="비운다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_restart" target="n_cache">
|
||||
<mxCell id="e_r-c" value="캐시 초기화" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_restart" target="n_cache">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="212.0" y="157.5" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_r-db" value="건드리지 않는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_restart" target="n_db">
|
||||
<mxCell id="e_r-db" value="변경 없음" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_restart" target="n_db">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="335.5" y="151.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
{
|
||||
"id": "edge-label-db-rt",
|
||||
"type": "text",
|
||||
"x": 279.0,
|
||||
"x": 286.0,
|
||||
"y": 332.0,
|
||||
"width": 104,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "세션이 남아 있어 통한다",
|
||||
"text": "세션 조회",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "세션이 남아 있어 통한다",
|
||||
"originalText": "세션 조회",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -193,11 +193,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "비운다",
|
||||
"text": "캐시 초기화",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "비운다",
|
||||
"originalText": "캐시 초기화",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "건드리지 않는다",
|
||||
"text": "변경 없음",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "건드리지 않는다",
|
||||
"originalText": "변경 없음",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "a8-cache-vs-session",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "60ae0f0551684a3d013de2a0eca5a41d5edf858f99511c29441388c02f7310c2",
|
||||
"spec_sha256": "02e971c0aedba252dce01773d7896eb2a751cd8752eb14d643b43e8f96646102",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,6 +5,6 @@ flowchart TB
|
||||
n1["Infinispan sessions 캐시"]
|
||||
n2[("PostgreSQL 세션 행")]
|
||||
n3["재시작 전 발급한 refresh token"]
|
||||
n0 -->|"비운다"| n1
|
||||
n0 -->|"건드리지 않는다"| n2
|
||||
n2 -->|"세션이 남아 있어 통한다"| n3
|
||||
n0 -->|"캐시 초기화"| n1
|
||||
n0 -->|"변경 없음"| n2
|
||||
n2 -->|"세션 조회"| n3
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="556" />
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="393.0,324.0 393.0,372.0 269.0,372.0 269.0,420.0" data-evidence="270-278" />
|
||||
<rect class="edge-label-bg" x="278.4" y="330.0" width="105.1" height="22" rx="3" />
|
||||
<text class="edge-label" x="331.0" y="345.0">세션이 남아 있어 통한다</text>
|
||||
<rect class="edge-label-bg" x="305.2" y="330.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="331.0" y="345.0">세션 조회</text>
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="260.0,131.0 260.0,185.5 164.0,185.5 164.0,240.0" data-evidence="270-278" />
|
||||
<rect class="edge-label-bg" x="190.0" y="143.5" width="44.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="212.0" y="158.5">비운다</text>
|
||||
<rect class="edge-label-bg" x="182.9" y="143.5" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="212.0" y="158.5">캐시 초기화</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="278.0,131.0 278.0,179.0 393.0,179.0 393.0,227.0" data-evidence="270-278" />
|
||||
<rect class="edge-label-bg" x="299.7" y="137.0" width="71.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="335.5" y="152.0">건드리지 않는다</text>
|
||||
<rect class="edge-label-bg" x="309.8" y="137.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="335.5" y="152.0">변경 없음</text>
|
||||
<g id="node-restart">
|
||||
<rect class="node-shape kind-process emphasis-primary role-source" data-evidence="270-274" x="171.5" y="60.0" width="195.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="269.0" y="87.0">롤링 재시작</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@@ -17,6 +17,6 @@
|
||||
|
||||
## Relationships
|
||||
|
||||
- **브라우저 A 세션 → 토큰 행:** principal 이름으로 쓴다. Evidence: L370–L377.
|
||||
- **브라우저 B 세션 → 토큰 행:** 같은 키로 덮어쓴다. Evidence: L370–L377.
|
||||
- **토큰 행 → 로그아웃 후 남는 것:** 로그아웃이 정리하지 않는다. Evidence: L378–L384.
|
||||
- **브라우저 A 세션 → 토큰 행:** principal 이름. Evidence: L370–L377.
|
||||
- **브라우저 B 세션 → 토큰 행:** 같은 키 · 덮어쓰기. Evidence: L370–L377.
|
||||
- **토큰 행 → 로그아웃 후 남는 것:** 로그아웃 미정리. Evidence: L378–L384.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "토큰 행" {
|
||||
n3: "로그아웃 후 남는 것" {
|
||||
shape: cylinder
|
||||
}
|
||||
n0 -> n2: "principal 이름으로 쓴다"
|
||||
n1 -> n2: "같은 키로 덮어쓴다"
|
||||
n2 -> n3: "로그아웃이 정리하지 않는다"
|
||||
n0 -> n2: "principal 이름"
|
||||
n1 -> n2: "같은 키 · 덮어쓰기"
|
||||
n2 -> n3: "로그아웃 미정리"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="브라우저 B 세션", shape=box, style="rounded,filled"];
|
||||
n2 [label="토큰 행", shape=cylinder, style="rounded,filled"];
|
||||
n3 [label="로그아웃 후 남는 것", shape=cylinder, style="rounded,filled"];
|
||||
n0 -> n2 [label="principal 이름으로 쓴다", style=solid];
|
||||
n1 -> n2 [label="같은 키로 덮어쓴다", style=solid];
|
||||
n2 -> n3 [label="로그아웃이 정리하지 않는다", style=solid];
|
||||
n0 -> n2 [label="principal 이름", style=solid];
|
||||
n1 -> n2 [label="같은 키 · 덮어쓰기", style=solid];
|
||||
n2 -> n3 [label="로그아웃 미정리", style=solid];
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
<mxCell id="n_leftover" value="로그아웃 후 남는 것<br/>평문 refresh token" tooltip="Redis 세션은 0 키인데 여기는 1 행이 남는다. | Evidence: L378-L384" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="175.0" y="413.0" width="150.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_s1-t" value="principal 이름으로 쓴다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_s1" target="n_token-row">
|
||||
<mxCell id="e_s1-t" value="principal 이름" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_s1" target="n_token-row">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="193.0" y="144.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_s2-t" value="같은 키로 덮어쓴다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_s2" target="n_token-row">
|
||||
<mxCell id="e_s2-t" value="같은 키 · 덮어쓰기" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_s2" target="n_token-row">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="307.0" y="144.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_t-l" value="로그아웃이 정리하지 않는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_token-row" target="n_leftover">
|
||||
<mxCell id="e_t-l" value="로그아웃 미정리" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_token-row" target="n_leftover">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="274.0" y="365.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
{
|
||||
"id": "edge-label-s1-t",
|
||||
"type": "text",
|
||||
"x": 125.0,
|
||||
"x": 145.0,
|
||||
"y": 132.0,
|
||||
"width": 136,
|
||||
"width": 96,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "principal 이름으로 쓴다",
|
||||
"text": "principal 이름",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "principal 이름으로 쓴다",
|
||||
"originalText": "principal 이름",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -193,11 +193,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "같은 키로 덮어쓴다",
|
||||
"text": "같은 키 · 덮어쓰기",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "같은 키로 덮어쓴다",
|
||||
"originalText": "같은 키 · 덮어쓰기",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -264,9 +264,9 @@
|
||||
{
|
||||
"id": "edge-label-t-l",
|
||||
"type": "text",
|
||||
"x": 218.0,
|
||||
"x": 229.0,
|
||||
"y": 353.0,
|
||||
"width": 112,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "로그아웃이 정리하지 않는다",
|
||||
"text": "로그아웃 미정리",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "로그아웃이 정리하지 않는다",
|
||||
"originalText": "로그아웃 미정리",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "b2-primary-key-overwrite",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "653f795b5dd9a627e79a865316e22d8d7ca35f86cbdf6e72dea25c631687cadf",
|
||||
"spec_sha256": "88795858ea78e4c8a0f6fca3a6131c36883a2378246384b83b9d31b636a7b5a4",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,6 +5,6 @@ flowchart TB
|
||||
n1["브라우저 B 세션"]
|
||||
n2[("토큰 행")]
|
||||
n3[("로그아웃 후 남는 것")]
|
||||
n0 -->|"principal 이름으로 쓴다"| n2
|
||||
n1 -->|"같은 키로 덮어쓴다"| n2
|
||||
n2 -->|"로그아웃이 정리하지 않는다"| n3
|
||||
n0 -->|"principal 이름"| n2
|
||||
n1 -->|"같은 키 · 덮어쓰기"| n2
|
||||
n2 -->|"로그아웃 미정리"| n3
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="555" />
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="145.0,124.0 145.0,172.0 241.0,172.0 241.0,220.0" data-evidence="370-377" />
|
||||
<rect class="edge-label-bg" x="127.0" y="130.0" width="131.9" height="22" rx="3" />
|
||||
<text class="edge-label" x="193.0" y="145.0">principal 이름으로 쓴다</text>
|
||||
<rect class="edge-label-bg" x="143.8" y="130.0" width="98.4" height="22" rx="3" />
|
||||
<text class="edge-label" x="193.0" y="145.0">principal 이름</text>
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="355.0,124.0 355.0,172.0 259.0,172.0 259.0,220.0" data-evidence="370-377" />
|
||||
<rect class="edge-label-bg" x="264.5" y="130.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="307.0" y="145.0">같은 키로 덮어쓴다</text>
|
||||
<rect class="edge-label-bg" x="261.1" y="130.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="307.0" y="145.0">같은 키 · 덮어쓰기</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="250.0,317.0 250.0,365.0 250.0,365.0 250.0,413.0" data-evidence="378-384" />
|
||||
<rect class="edge-label-bg" x="218.1" y="351.0" width="111.8" height="22" rx="3" />
|
||||
<text class="edge-label" x="274.0" y="366.0">로그아웃이 정리하지 않는다</text>
|
||||
<rect class="edge-label-bg" x="238.2" y="351.0" width="71.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="274.0" y="366.0">로그아웃 미정리</text>
|
||||
<g id="node-s1">
|
||||
<rect class="node-shape kind-component emphasis-primary role-source" data-evidence="360-366" x="70.0" y="60.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="145.0" y="90.0">브라우저 A 세션</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -18,5 +18,5 @@ revokeRefreshToken 을 켜고 refreshTokenMaxReuse 를 0 으로 둔 상태에서
|
||||
## Relationships
|
||||
|
||||
- **동시 refresh 5건 → 회전 검사:** 동시 도착. Evidence: L369–L377.
|
||||
- **client session → 이긴 요청의 새 토큰:** 세션이 없으니 못 쓴다. Evidence: L378–L384.
|
||||
- **client session → 이긴 요청의 새 토큰:** 사용 불가. Evidence: L378–L384.
|
||||
- **회전 검사 → client session:** 경쟁 감지 시 삭제. Evidence: L378–L384.
|
||||
|
||||
@@ -15,4 +15,4 @@ n3: "이긴 요청의 새 토큰" {
|
||||
}
|
||||
n0 -> n1: "동시 도착"
|
||||
n1 -> n2: "경쟁 감지 시 삭제"
|
||||
n2 -> n3: "세션이 없으니 못 쓴다"
|
||||
n2 -> n3: "사용 불가"
|
||||
|
||||
@@ -8,5 +8,5 @@ digraph techviz {
|
||||
n3 [label="이긴 요청의 새 토큰", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="동시 도착", style=solid];
|
||||
n1 -> n2 [label="경쟁 감지 시 삭제", style=solid];
|
||||
n2 -> n3 [label="세션이 없으니 못 쓴다", style=solid];
|
||||
n2 -> n3 [label="사용 불가", style=solid];
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_concurrent" value="동시 refresh 5건<br/>& 와 wait 이 없으면 재현되지 않는다" tooltip="같은 refresh token 을 쓴다. | Evidence: L369-L375" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="135.0" y="60.0" width="170.0" height="84.0" as="geometry"/>
|
||||
<mxCell id="n_concurrent" value="동시 refresh 5건<br/>& + wait 필요" tooltip="같은 refresh token 을 쓴다. | Evidence: L369-L375" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="145.0" y="60.0" width="150.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_rotation" value="회전 검사<br/>revokeRefreshToken=true · refreshTokenMaxReuse=0" tooltip="이미 쓴 토큰인지 본다. | Evidence: L369-L377" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="300.0" height="71.0" as="geometry"/>
|
||||
@@ -22,7 +22,7 @@
|
||||
<mxPoint x="244.0" y="192.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_cs-nt" value="세션이 없으니 못 쓴다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client-session" target="n_new-token">
|
||||
<mxCell id="e_cs-nt" value="사용 불가" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client-session" target="n_new-token">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="244.0" y="519.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -165,9 +165,9 @@
|
||||
{
|
||||
"id": "edge-label-cs-nt",
|
||||
"type": "text",
|
||||
"x": 196.0,
|
||||
"x": 199.0,
|
||||
"y": 507.0,
|
||||
"width": 96,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -193,11 +193,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "세션이 없으니 못 쓴다",
|
||||
"text": "사용 불가",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "세션이 없으니 못 쓴다",
|
||||
"originalText": "사용 불가",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -303,9 +303,9 @@
|
||||
{
|
||||
"id": "node-concurrent",
|
||||
"type": "rectangle",
|
||||
"x": 135.0,
|
||||
"x": 145.0,
|
||||
"y": 60.0,
|
||||
"width": 170.0,
|
||||
"width": 150.0,
|
||||
"height": 84.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -333,9 +333,9 @@
|
||||
{
|
||||
"id": "node-label-concurrent",
|
||||
"type": "text",
|
||||
"x": 145.0,
|
||||
"x": 155.0,
|
||||
"y": 70.0,
|
||||
"width": 150.0,
|
||||
"width": 130.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -361,11 +361,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "동시 refresh 5건\n& 와 wait 이 없으면 재현되지 않는다",
|
||||
"text": "동시 refresh 5건\n& + wait 필요",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "동시 refresh 5건\n& 와 wait 이 없으면 재현되지 않는다",
|
||||
"originalText": "동시 refresh 5건\n& + wait 필요",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "b3-rotation-contention",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "3fbbe8b3528bbcc2ad23e48a820e9ddc6fe6072857bfbe2fa3df0e566fe99162",
|
||||
"spec_sha256": "31779474e5400d5e719faf81a62da35a657994d952e4e0324a1c76c5d18183e4",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -7,6 +7,6 @@ flowchart TB
|
||||
n3["이긴 요청의 새 토큰"]
|
||||
n0 -->|"동시 도착"| n1
|
||||
n1 -->|"경쟁 감지 시 삭제"| n2
|
||||
n2 -->|"세션이 없으니 못 쓴다"| n3
|
||||
n2 -->|"사용 불가"| n3
|
||||
classDef external stroke-dasharray: 6 4
|
||||
class n0 external
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
<rect class="edge-label-bg" x="218.2" y="178.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="244.0" y="193.0">동시 도착</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="220.0,471.0 220.0,519.0 220.0,519.0 220.0,567.0" data-evidence="378-384" />
|
||||
<rect class="edge-label-bg" x="194.8" y="505.0" width="98.4" height="22" rx="3" />
|
||||
<text class="edge-label" x="244.0" y="520.0">세션이 없으니 못 쓴다</text>
|
||||
<rect class="edge-label-bg" x="218.2" y="505.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="244.0" y="520.0">사용 불가</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="220.0,311.0 220.0,359.0 220.0,359.0 220.0,407.0" data-evidence="378-384" />
|
||||
<rect class="edge-label-bg" x="201.5" y="345.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="244.0" y="360.0">경쟁 감지 시 삭제</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
@@ -18,5 +18,5 @@ nginx 는 자기가 proxy_set_header 로 설정한 헤더만 덮어쓴다. 설
|
||||
## Relationships
|
||||
|
||||
- **밖에서 보낸 위조 헤더 → nginx:** 위조 헤더. Evidence: L393–L400.
|
||||
- **nginx → oauth2-proxy:** 지우지 않으면 그대로 지난다. Evidence: L393–L400.
|
||||
- **nginx → oauth2-proxy:** 미삭제 시 통과. Evidence: L393–L400.
|
||||
- **oauth2-proxy → 앱:** 인가 헤더. Evidence: L393–L408.
|
||||
|
||||
@@ -14,5 +14,5 @@ n3: "앱" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "위조 헤더"
|
||||
n1 -> n2: "지우지 않으면 그대로 지난다"
|
||||
n1 -> n2: "미삭제 시 통과"
|
||||
n2 -> n3: "인가 헤더"
|
||||
|
||||
@@ -7,6 +7,6 @@ digraph techviz {
|
||||
n2 [label="oauth2-proxy", shape=diamond, style="rounded,filled"];
|
||||
n3 [label="앱", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="위조 헤더", style=solid];
|
||||
n1 -> n2 [label="지우지 않으면 그대로 지난다", style=solid];
|
||||
n1 -> n2 [label="미삭제 시 통과", style=solid];
|
||||
n2 -> n3 [label="인가 헤더", style=solid];
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_attacker" value="밖에서 보낸 위조 헤더<br/>X-Auth-Request-Roles" tooltip="앱이 믿는 이름을 그대로 쓴다. | Evidence: L393-L400" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="124.5" y="60.0" width="170.0" height="84.0" as="geometry"/>
|
||||
<mxGeometry x="82.5" y="60.0" width="170.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_nginx" value="nginx<br/>proxy_set_header ... "" 로 먼저 지워야 한다" tooltip="설정하지 않은 이름은 덮어쓰지 않는다. | Evidence: L393-L400" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rhombus;perimeter=rhombusPerimeter;fillColor=#fff7e8;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="279.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_nginx" value="nginx<br/>proxy_set_header ... """ tooltip="설정하지 않은 이름은 덮어쓰지 않는다. | Evidence: L393-L400" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rhombus;perimeter=rhombusPerimeter;fillColor=#fff7e8;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="195.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_proxy" value="oauth2-proxy<br/>--set-xauthrequest" tooltip="인증 결과를 헤더로 넣는다. | Evidence: L393-L400" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rhombus;perimeter=rhombusPerimeter;fillColor=#fff7e8;" vertex="1" parent="1">
|
||||
<mxGeometry x="129.5" y="407.0" width="160.0" height="71.0" as="geometry"/>
|
||||
<mxGeometry x="87.5" y="407.0" width="160.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_app" value="앱<br/>세션은 로그인 시점의 스냅샷" tooltip="헤더를 믿고 인가한다. | Evidence: L401-L408" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="134.5" y="574.0" width="150.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_app" value="앱<br/>로그인 시점 스냅샷" tooltip="헤더를 믿고 인가한다. | Evidence: L401-L408" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="92.5" y="574.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_a-n" value="위조 헤더" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_attacker" target="n_nginx">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="233.5" y="192.0" as="offset"/>
|
||||
<mxPoint x="191.5" y="192.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_n-p" value="지우지 않으면 그대로 지난다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_nginx" target="n_proxy">
|
||||
<mxCell id="e_n-p" value="미삭제 시 통과" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_nginx" target="n_proxy">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="233.5" y="359.0" as="offset"/>
|
||||
<mxPoint x="191.5" y="359.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_p-a" value="인가 헤더" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_proxy" target="n_app">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="233.5" y="526.0" as="offset"/>
|
||||
<mxPoint x="191.5" y="526.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"id": "edge-a-n",
|
||||
"type": "arrow",
|
||||
"x": 209.5,
|
||||
"x": 167.5,
|
||||
"y": 144.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -66,7 +66,7 @@
|
||||
{
|
||||
"id": "edge-label-a-n",
|
||||
"type": "text",
|
||||
"x": 188.5,
|
||||
"x": 146.5,
|
||||
"y": 180.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -105,7 +105,7 @@
|
||||
{
|
||||
"id": "edge-n-p",
|
||||
"type": "arrow",
|
||||
"x": 209.5,
|
||||
"x": 167.5,
|
||||
"y": 311.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -165,9 +165,9 @@
|
||||
{
|
||||
"id": "edge-label-n-p",
|
||||
"type": "text",
|
||||
"x": 173.5,
|
||||
"x": 146.5,
|
||||
"y": 347.0,
|
||||
"width": 120,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -193,18 +193,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "지우지 않으면 그대로 지난다",
|
||||
"text": "미삭제 시 통과",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "지우지 않으면 그대로 지난다",
|
||||
"originalText": "미삭제 시 통과",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-p-a",
|
||||
"type": "arrow",
|
||||
"x": 209.5,
|
||||
"x": 167.5,
|
||||
"y": 478.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -264,7 +264,7 @@
|
||||
{
|
||||
"id": "edge-label-p-a",
|
||||
"type": "text",
|
||||
"x": 188.5,
|
||||
"x": 146.5,
|
||||
"y": 514.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -303,7 +303,7 @@
|
||||
{
|
||||
"id": "node-attacker",
|
||||
"type": "rectangle",
|
||||
"x": 124.5,
|
||||
"x": 82.5,
|
||||
"y": 60.0,
|
||||
"width": 170.0,
|
||||
"height": 84.0,
|
||||
@@ -333,7 +333,7 @@
|
||||
{
|
||||
"id": "node-label-attacker",
|
||||
"type": "text",
|
||||
"x": 134.5,
|
||||
"x": 92.5,
|
||||
"y": 70.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
@@ -374,7 +374,7 @@
|
||||
"type": "rectangle",
|
||||
"x": 70.0,
|
||||
"y": 240.0,
|
||||
"width": 279.0,
|
||||
"width": 195.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -404,7 +404,7 @@
|
||||
"type": "text",
|
||||
"x": 80.0,
|
||||
"y": 250.0,
|
||||
"width": 259.0,
|
||||
"width": 175.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -430,18 +430,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "nginx\nproxy_set_header ... \"\" 로 먼저 지워야 한다",
|
||||
"text": "nginx\nproxy_set_header ... \"\"",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "nginx\nproxy_set_header ... \"\" 로 먼저 지워야 한다",
|
||||
"originalText": "nginx\nproxy_set_header ... \"\"",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-proxy",
|
||||
"type": "rectangle",
|
||||
"x": 129.5,
|
||||
"x": 87.5,
|
||||
"y": 407.0,
|
||||
"width": 160.0,
|
||||
"height": 71.0,
|
||||
@@ -471,7 +471,7 @@
|
||||
{
|
||||
"id": "node-label-proxy",
|
||||
"type": "text",
|
||||
"x": 139.5,
|
||||
"x": 97.5,
|
||||
"y": 417.0,
|
||||
"width": 140.0,
|
||||
"height": 51.0,
|
||||
@@ -510,7 +510,7 @@
|
||||
{
|
||||
"id": "node-app",
|
||||
"type": "rectangle",
|
||||
"x": 134.5,
|
||||
"x": 92.5,
|
||||
"y": 574.0,
|
||||
"width": 150.0,
|
||||
"height": 71.0,
|
||||
@@ -540,7 +540,7 @@
|
||||
{
|
||||
"id": "node-label-app",
|
||||
"type": "text",
|
||||
"x": 144.5,
|
||||
"x": 102.5,
|
||||
"y": 584.0,
|
||||
"width": 130.0,
|
||||
"height": 51.0,
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "앱\n세션은 로그인 시점의 스냅샷",
|
||||
"text": "앱\n로그인 시점 스냅샷",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "앱\n세션은 로그인 시점의 스냅샷",
|
||||
"originalText": "앱\n로그인 시점 스냅샷",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "b4-header-trust-boundary",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "9ae5cf39dfc20e31d81b892ae7483d2b9ccf94fa2c91a03837200b463bfc1103",
|
||||
"spec_sha256": "56747d5f7826ad63f202d8dc4d6a4f1323f12eeaedb4bf989b67d0bfab5f09cd",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -6,7 +6,7 @@ flowchart TB
|
||||
n2{"oauth2-proxy"}
|
||||
n3["앱"]
|
||||
n0 -->|"위조 헤더"| n1
|
||||
n1 -->|"지우지 않으면 그대로 지난다"| n2
|
||||
n1 -->|"미삭제 시 통과"| n2
|
||||
n2 -->|"인가 헤더"| n3
|
||||
classDef external stroke-dasharray: 6 4
|
||||
class n0 external
|
||||
|
||||
@@ -50,35 +50,35 @@
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="690" />
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="209.5,144.0 209.5,192.0 209.5,192.0 209.5,240.0" data-evidence="393-400" />
|
||||
<rect class="edge-label-bg" x="207.8" y="178.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="233.5" y="193.0">위조 헤더</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="209.5,311.0 209.5,359.0 209.5,359.0 209.5,407.0" data-evidence="393-400" />
|
||||
<rect class="edge-label-bg" x="174.2" y="345.0" width="118.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="233.5" y="360.0">지우지 않으면 그대로 지난다</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="209.5,478.0 209.5,526.0 209.5,526.0 209.5,574.0" data-evidence="393-408" />
|
||||
<rect class="edge-label-bg" x="207.8" y="512.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="233.5" y="527.0">인가 헤더</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="167.5,144.0 167.5,192.0 167.5,192.0 167.5,240.0" data-evidence="393-400" />
|
||||
<rect class="edge-label-bg" x="165.8" y="178.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="193.0">위조 헤더</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="167.5,311.0 167.5,359.0 167.5,359.0 167.5,407.0" data-evidence="393-400" />
|
||||
<rect class="edge-label-bg" x="155.7" y="345.0" width="71.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="360.0">미삭제 시 통과</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="167.5,478.0 167.5,526.0 167.5,526.0 167.5,574.0" data-evidence="393-408" />
|
||||
<rect class="edge-label-bg" x="165.8" y="512.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="191.5" y="527.0">인가 헤더</text>
|
||||
<g id="node-attacker">
|
||||
<g class="actor-symbol emphasis-warning" data-evidence="393-400"><circle cx="209.5" cy="80.0" r="11.0" /><line x1="209.5" y1="96.0" x2="209.5" y2="105.0" /><line x1="191.5" y1="106.0" x2="227.5" y2="106.0" /><line x1="209.5" y1="105.0" x2="194.5" y2="122.0" /><line x1="209.5" y1="105.0" x2="224.5" y2="122.0" /></g>
|
||||
<text class="node-label" x="209.5" y="137.0">밖에서 보낸 위조 헤더</text>
|
||||
<g class="actor-symbol emphasis-warning" data-evidence="393-400"><circle cx="167.5" cy="80.0" r="11.0" /><line x1="167.5" y1="96.0" x2="167.5" y2="105.0" /><line x1="149.5" y1="106.0" x2="185.5" y2="106.0" /><line x1="167.5" y1="105.0" x2="152.5" y2="122.0" /><line x1="167.5" y1="105.0" x2="182.5" y2="122.0" /></g>
|
||||
<text class="node-label" x="167.5" y="137.0">밖에서 보낸 위조 헤더</text>
|
||||
</g>
|
||||
<g id="node-nginx">
|
||||
<polygon class="node-shape kind-gateway emphasis-warning role-control" data-evidence="393-400" points="209.5,240.0 349.0,275.5 209.5,311.0 70.0,275.5" />
|
||||
<text class="node-label" x="209.5" y="267.0">nginx</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="288.0" x2="335.0" y2="288.0" />
|
||||
<text class="node-detail" x="86.0" y="305.0">proxy_set_header ... "" 로 먼저 지워야 한다</text>
|
||||
<polygon class="node-shape kind-gateway emphasis-warning role-control" data-evidence="393-400" points="167.5,240.0 265.0,275.5 167.5,311.0 70.0,275.5" />
|
||||
<text class="node-label" x="167.5" y="267.0">nginx</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="288.0" x2="251.0" y2="288.0" />
|
||||
<text class="node-detail" x="86.0" y="305.0">proxy_set_header ... ""</text>
|
||||
</g>
|
||||
<g id="node-proxy">
|
||||
<polygon class="node-shape kind-gateway emphasis-normal role-control" data-evidence="393-400" points="209.5,407.0 289.5,442.5 209.5,478.0 129.5,442.5" />
|
||||
<text class="node-label" x="209.5" y="434.0">oauth2-proxy</text>
|
||||
<line class="node-detail-divider" x1="143.5" y1="455.0" x2="275.5" y2="455.0" />
|
||||
<text class="node-detail" x="145.5" y="472.0">--set-xauthrequest</text>
|
||||
<polygon class="node-shape kind-gateway emphasis-normal role-control" data-evidence="393-400" points="167.5,407.0 247.5,442.5 167.5,478.0 87.5,442.5" />
|
||||
<text class="node-label" x="167.5" y="434.0">oauth2-proxy</text>
|
||||
<line class="node-detail-divider" x1="101.5" y1="455.0" x2="233.5" y2="455.0" />
|
||||
<text class="node-detail" x="103.5" y="472.0">--set-xauthrequest</text>
|
||||
</g>
|
||||
<g id="node-app">
|
||||
<rect class="node-shape kind-service emphasis-primary role-target" data-evidence="401-408" x="134.5" y="574.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="209.5" y="601.0">앱</text>
|
||||
<line class="node-detail-divider" x1="148.5" y1="622.0" x2="270.5" y2="622.0" />
|
||||
<text class="node-detail" x="150.5" y="639.0">세션은 로그인 시점의 스냅샷</text>
|
||||
<rect class="node-shape kind-service emphasis-primary role-target" data-evidence="401-408" x="92.5" y="574.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="167.5" y="601.0">앱</text>
|
||||
<line class="node-detail-divider" x1="106.5" y1="622.0" x2="228.5" y2="622.0" />
|
||||
<text class="node-detail" x="108.5" y="639.0">로그인 시점 스냅샷</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
@@ -17,6 +17,6 @@ redis-cli config set appendonly yes 를 켜도 아무것도 달라지지 않았
|
||||
|
||||
## Relationships
|
||||
|
||||
- **appendonly yes → /data:** AOF 파일을 쓴다. Evidence: L406–L412.
|
||||
- **/data → 컨테이너:** 컨테이너와 함께 죽는다. Evidence: L406–L412.
|
||||
- **/data → PersistentVolume:** 볼륨을 붙여야 남는다. Evidence: L406–L412.
|
||||
- **appendonly yes → /data:** AOF 기록. Evidence: L406–L412.
|
||||
- **/data → 컨테이너:** 컨테이너와 함께 소멸. Evidence: L406–L412.
|
||||
- **/data → PersistentVolume:** 볼륨 마운트. Evidence: L406–L412.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "컨테이너" {
|
||||
n3: "PersistentVolume" {
|
||||
shape: cylinder
|
||||
}
|
||||
n0 -> n1: "AOF 파일을 쓴다"
|
||||
n1 -> n2: "컨테이너와 함께 죽는다"
|
||||
n1 -> n3: "볼륨을 붙여야 남는다"
|
||||
n0 -> n1: "AOF 기록"
|
||||
n1 -> n2: "컨테이너와 함께 소멸"
|
||||
n1 -> n3: "볼륨 마운트"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="/data", shape=cylinder, style="rounded,filled"];
|
||||
n2 [label="컨테이너", shape=box, style="rounded,filled"];
|
||||
n3 [label="PersistentVolume", shape=cylinder, style="rounded,filled"];
|
||||
n0 -> n1 [label="AOF 파일을 쓴다", style=solid];
|
||||
n1 -> n2 [label="컨테이너와 함께 죽는다", style=solid];
|
||||
n1 -> n3 [label="볼륨을 붙여야 남는다", style=solid];
|
||||
n0 -> n1 [label="AOF 기록", style=solid];
|
||||
n1 -> n2 [label="컨테이너와 함께 소멸", style=solid];
|
||||
n1 -> n3 [label="볼륨 마운트", style=solid];
|
||||
}
|
||||
|
||||
@@ -8,26 +8,26 @@
|
||||
<mxCell id="n_config" value="appendonly yes<br/>redis-cli config set" tooltip="설정은 적용된다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="163.0" y="60.0" width="174.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_datadir" value="/data<br/>appendonlydir 이 만들어졌다 버려진다" tooltip="컨테이너 파일시스템이다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="142.0" y="227.0" width="216.0" height="97.0" as="geometry"/>
|
||||
<mxCell id="n_datadir" value="/data<br/>appendonlydir" tooltip="컨테이너 파일시스템이다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="175.0" y="227.0" width="150.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_container" value="컨테이너<br/>볼륨이 없으면 여기까지다" tooltip="죽으면 /data 도 같이 사라진다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxCell id="n_container" value="컨테이너<br/>볼륨 없음" tooltip="죽으면 /data 도 같이 사라진다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="429.5" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_volume" value="PersistentVolume" tooltip="여기 있어야 설정이 뜻을 갖는다. | Evidence: L406-L412" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="280.0" y="420.0" width="150.0" height="90.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_c-d" value="AOF 파일을 쓴다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_config" target="n_datadir">
|
||||
<mxCell id="e_c-d" value="AOF 기록" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_config" target="n_datadir">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="274.0" y="179.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_d-c" value="컨테이너와 함께 죽는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_datadir" target="n_container">
|
||||
<mxCell id="e_d-c" value="컨테이너와 함께 소멸" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_datadir" target="n_container">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="193.0" y="348.8" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_d-v" value="볼륨을 붙여야 남는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_datadir" target="n_volume">
|
||||
<mxCell id="e_d-v" value="볼륨 마운트" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_datadir" target="n_volume">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="307.0" y="344.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "AOF 파일을 쓴다",
|
||||
"text": "AOF 기록",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "AOF 파일을 쓴다",
|
||||
"originalText": "AOF 기록",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -165,9 +165,9 @@
|
||||
{
|
||||
"id": "edge-label-d-c",
|
||||
"type": "text",
|
||||
"x": 145.0,
|
||||
"x": 148.0,
|
||||
"y": 336.75,
|
||||
"width": 96,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -193,11 +193,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "컨테이너와 함께 죽는다",
|
||||
"text": "컨테이너와 함께 소멸",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "컨테이너와 함께 죽는다",
|
||||
"originalText": "컨테이너와 함께 소멸",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "볼륨을 붙여야 남는다",
|
||||
"text": "볼륨 마운트",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "볼륨을 붙여야 남는다",
|
||||
"originalText": "볼륨 마운트",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -372,9 +372,9 @@
|
||||
{
|
||||
"id": "node-datadir",
|
||||
"type": "rectangle",
|
||||
"x": 142.0,
|
||||
"x": 175.0,
|
||||
"y": 227.0,
|
||||
"width": 216.0,
|
||||
"width": 150.0,
|
||||
"height": 97.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -402,9 +402,9 @@
|
||||
{
|
||||
"id": "node-label-datadir",
|
||||
"type": "text",
|
||||
"x": 152.0,
|
||||
"x": 185.0,
|
||||
"y": 237.0,
|
||||
"width": 196.0,
|
||||
"width": 130.0,
|
||||
"height": 77.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -430,11 +430,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "/data\nappendonlydir 이 만들어졌다 버려진다",
|
||||
"text": "/data\nappendonlydir",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "/data\nappendonlydir 이 만들어졌다 버려진다",
|
||||
"originalText": "/data\nappendonlydir",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -499,11 +499,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "컨테이너\n볼륨이 없으면 여기까지다",
|
||||
"text": "컨테이너\n볼륨 없음",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "컨테이너\n볼륨이 없으면 여기까지다",
|
||||
"originalText": "컨테이너\n볼륨 없음",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "b5-b6-storage-and-keys",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "51b618881bf3ef23a734b2beb319e756c12a9a7ff1ae578b7b5ef78a1461b0e9",
|
||||
"spec_sha256": "6be204030cc95c5d9aec2ec4f07eae62bd88e7f344d00c2e014a20e18d6f8dba",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,6 +5,6 @@ flowchart TB
|
||||
n1[("/data")]
|
||||
n2["컨테이너"]
|
||||
n3[("PersistentVolume")]
|
||||
n0 -->|"AOF 파일을 쓴다"| n1
|
||||
n1 -->|"컨테이너와 함께 죽는다"| n2
|
||||
n1 -->|"볼륨을 붙여야 남는다"| n3
|
||||
n0 -->|"AOF 기록"| n1
|
||||
n1 -->|"컨테이너와 함께 소멸"| n2
|
||||
n1 -->|"볼륨 마운트"| n3
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="555" />
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="250.0,131.0 250.0,179.0 250.0,179.0 250.0,227.0" data-evidence="406-412" />
|
||||
<rect class="edge-label-bg" x="231.5" y="165.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="274.0" y="180.0">AOF 파일을 쓴다</text>
|
||||
<rect class="edge-label-bg" x="244.9" y="165.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="274.0" y="180.0">AOF 기록</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="241.0,324.0 241.0,376.8 145.0,376.8 145.0,429.5" data-evidence="406-412" />
|
||||
<rect class="edge-label-bg" x="143.8" y="334.8" width="98.4" height="22" rx="3" />
|
||||
<text class="edge-label" x="193.0" y="349.8">컨테이너와 함께 죽는다</text>
|
||||
<rect class="edge-label-bg" x="147.2" y="334.8" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="193.0" y="349.8">컨테이너와 함께 소멸</text>
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="259.0,324.0 259.0,372.0 355.0,372.0 355.0,420.0" data-evidence="406-412" />
|
||||
<rect class="edge-label-bg" x="261.1" y="330.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="307.0" y="345.0">볼륨을 붙여야 남는다</text>
|
||||
<rect class="edge-label-bg" x="277.9" y="330.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="307.0" y="345.0">볼륨 마운트</text>
|
||||
<g id="node-config">
|
||||
<rect class="node-shape kind-process emphasis-warning role-source" data-evidence="406-412" x="163.0" y="60.0" width="174.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="250.0" y="87.0">appendonly yes</text>
|
||||
@@ -66,16 +66,16 @@
|
||||
<text class="node-detail" x="179.0" y="125.0">redis-cli config set</text>
|
||||
</g>
|
||||
<g id="node-datadir">
|
||||
<rect class="node-shape kind-datastore emphasis-warning role-control" data-evidence="406-412" x="142.0" y="240.0" width="216.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-warning role-control" cx="250.0" cy="240.0" rx="108.0" ry="13.0" /><path class="storage-bottom" d="M 142.0 311.0 A 108.0 13.0 0 0 0 358.0 311.0" />
|
||||
<rect class="node-shape kind-datastore emphasis-warning role-control" data-evidence="406-412" x="175.0" y="240.0" width="150.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-warning role-control" cx="250.0" cy="240.0" rx="75.0" ry="13.0" /><path class="storage-bottom" d="M 175.0 311.0 A 75.0 13.0 0 0 0 325.0 311.0" />
|
||||
<text class="node-label" x="250.0" y="267.0">/data</text>
|
||||
<line class="node-detail-divider" x1="156.0" y1="288.0" x2="344.0" y2="288.0" />
|
||||
<text class="node-detail" x="158.0" y="305.0">appendonlydir 이 만들어졌다 버려진다</text>
|
||||
<line class="node-detail-divider" x1="189.0" y1="288.0" x2="311.0" y2="288.0" />
|
||||
<text class="node-detail" x="191.0" y="305.0">appendonlydir</text>
|
||||
</g>
|
||||
<g id="node-container">
|
||||
<rect class="node-shape kind-component emphasis-warning role-target" data-evidence="406-412" x="70.0" y="429.5" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="145.0" y="456.5">컨테이너</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="477.5" x2="206.0" y2="477.5" />
|
||||
<text class="node-detail" x="86.0" y="494.5">볼륨이 없으면 여기까지다</text>
|
||||
<text class="node-detail" x="86.0" y="494.5">볼륨 없음</text>
|
||||
</g>
|
||||
<g id="node-volume">
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-target" data-evidence="406-412" x="280.0" y="433.0" width="150.0" height="64.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-target" cx="355.0" cy="433.0" rx="75.0" ry="13.0" /><path class="storage-bottom" d="M 280.0 497.0 A 75.0 13.0 0 0 0 430.0 497.0" />
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -17,6 +17,6 @@ oauth2-proxy 는 세션 전체를 쿠키에 담고 replica 는 같은 k8s Secret
|
||||
|
||||
## Relationships
|
||||
|
||||
- **Redis 의 세션 → TTL:** 생성 시각이 여기 남는다. Evidence: L441–L452.
|
||||
- **k8s Secret → 쿠키의 티켓:** 티켓을 암호화한다. Evidence: L419–L432.
|
||||
- **쿠키의 티켓 → Redis 의 세션:** 키 이름을 만든다. Evidence: L429–L438.
|
||||
- **Redis 의 세션 → TTL:** 생성 시각. Evidence: L441–L452.
|
||||
- **k8s Secret → 쿠키의 티켓:** 티켓 암호화. Evidence: L419–L432.
|
||||
- **쿠키의 티켓 → Redis 의 세션:** 키 이름 생성. Evidence: L429–L438.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "Redis 의 세션" {
|
||||
n3: "TTL" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "티켓을 암호화한다"
|
||||
n1 -> n2: "키 이름을 만든다"
|
||||
n2 -> n3: "생성 시각이 여기 남는다"
|
||||
n0 -> n1: "티켓 암호화"
|
||||
n1 -> n2: "키 이름 생성"
|
||||
n2 -> n3: "생성 시각"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="쿠키의 티켓", shape=box, style="rounded,filled"];
|
||||
n2 [label="Redis 의 세션", shape=cylinder, style="rounded,filled"];
|
||||
n3 [label="TTL", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="티켓을 암호화한다", style=solid];
|
||||
n1 -> n2 [label="키 이름을 만든다", style=solid];
|
||||
n2 -> n3 [label="생성 시각이 여기 남는다", style=solid];
|
||||
n0 -> n1 [label="티켓 암호화", style=solid];
|
||||
n1 -> n2 [label="키 이름 생성", style=solid];
|
||||
n2 -> n3 [label="생성 시각", style=solid];
|
||||
}
|
||||
|
||||
@@ -8,26 +8,26 @@
|
||||
<mxCell id="n_secret" value="k8s Secret<br/>--cookie-secret 은 단수" tooltip="모든 replica 가 같은 값을 읽는다. | Evidence: L419-L428" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="60.0" width="174.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_ticket" value="쿠키의 티켓<br/>secret 을 바꾸면 못 푼다" tooltip="세션 id 와 복호화 키가 함께 암호화되어 있다. | Evidence: L429-L438" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="80.5" y="253.0" width="153.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_ticket" value="쿠키의 티켓<br/>secret 교체 시 복호화 불가" tooltip="세션 id 와 복호화 키가 함께 암호화되어 있다. | Evidence: L429-L438" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="77.0" y="253.0" width="160.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_redis-session" value="Redis 의 세션<br/>고아로 남는다" tooltip="티켓을 못 풀면 어느 키인지도 모른다. | Evidence: L429-L440" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxCell id="n_redis-session" value="Redis 의 세션<br/>고아 세션" tooltip="티켓을 못 풀면 어느 키인지도 모른다. | Evidence: L429-L440" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="82.0" y="420.0" width="150.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_ttl" value="TTL<br/>역산으로 고아를 고른다" tooltip="요청으로 갱신되지 않아 생성 시각의 함수다. | Evidence: L441-L452" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_ttl" value="TTL<br/>생성 시각 역산" tooltip="요청으로 갱신되지 않아 생성 시각의 함수다. | Evidence: L441-L452" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="82.0" y="613.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_r-ttl" value="생성 시각이 여기 남는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_redis-session" target="n_ttl">
|
||||
<mxCell id="e_r-ttl" value="생성 시각" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_redis-session" target="n_ttl">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="181.0" y="565.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_s-t" value="티켓을 암호화한다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_secret" target="n_ticket">
|
||||
<mxCell id="e_s-t" value="티켓 암호화" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_secret" target="n_ticket">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="181.0" y="205.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_t-r" value="키 이름을 만든다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_ticket" target="n_redis-session">
|
||||
<mxCell id="e_t-r" value="키 이름 생성" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_ticket" target="n_redis-session">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="181.0" y="372.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
{
|
||||
"id": "edge-label-r-ttl",
|
||||
"type": "text",
|
||||
"x": 129.0,
|
||||
"x": 136.0,
|
||||
"y": 553.0,
|
||||
"width": 104,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "생성 시각이 여기 남는다",
|
||||
"text": "생성 시각",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "생성 시각이 여기 남는다",
|
||||
"originalText": "생성 시각",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -193,11 +193,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "티켓을 암호화한다",
|
||||
"text": "티켓 암호화",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "티켓을 암호화한다",
|
||||
"originalText": "티켓 암호화",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "키 이름을 만든다",
|
||||
"text": "키 이름 생성",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "키 이름을 만든다",
|
||||
"originalText": "키 이름 생성",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -372,9 +372,9 @@
|
||||
{
|
||||
"id": "node-ticket",
|
||||
"type": "rectangle",
|
||||
"x": 80.5,
|
||||
"x": 77.0,
|
||||
"y": 253.0,
|
||||
"width": 153.0,
|
||||
"width": 160.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -402,9 +402,9 @@
|
||||
{
|
||||
"id": "node-label-ticket",
|
||||
"type": "text",
|
||||
"x": 90.5,
|
||||
"x": 87.0,
|
||||
"y": 263.0,
|
||||
"width": 133.0,
|
||||
"width": 140.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -430,11 +430,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "쿠키의 티켓\nsecret 을 바꾸면 못 푼다",
|
||||
"text": "쿠키의 티켓\nsecret 교체 시 복호화 불가",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "쿠키의 티켓\nsecret 을 바꾸면 못 푼다",
|
||||
"originalText": "쿠키의 티켓\nsecret 교체 시 복호화 불가",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -499,11 +499,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "Redis 의 세션\n고아로 남는다",
|
||||
"text": "Redis 의 세션\n고아 세션",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Redis 의 세션\n고아로 남는다",
|
||||
"originalText": "Redis 의 세션\n고아 세션",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "TTL\n역산으로 고아를 고른다",
|
||||
"text": "TTL\n생성 시각 역산",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "TTL\n역산으로 고아를 고른다",
|
||||
"originalText": "TTL\n생성 시각 역산",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "b7-cookie-session-tradeoff",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "ae4774e0d8dfda387902c00a5d3c933672d4adf799cd6774760a74b8a1ad376a",
|
||||
"spec_sha256": "9a594212157672a9188e296e73a0ab9af3d53992c94afdbfe2e1aeedaf8998bc",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,6 +5,6 @@ flowchart TB
|
||||
n1["쿠키의 티켓"]
|
||||
n2[("Redis 의 세션")]
|
||||
n3["TTL"]
|
||||
n0 -->|"티켓을 암호화한다"| n1
|
||||
n1 -->|"키 이름을 만든다"| n2
|
||||
n2 -->|"생성 시각이 여기 남는다"| n3
|
||||
n0 -->|"티켓 암호화"| n1
|
||||
n1 -->|"키 이름 생성"| n2
|
||||
n2 -->|"생성 시각"| n3
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="729" />
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="157.0,517.0 157.0,565.0 157.0,565.0 157.0,613.0" data-evidence="441-452" />
|
||||
<rect class="edge-label-bg" x="128.4" y="551.0" width="105.1" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="566.0">생성 시각이 여기 남는다</text>
|
||||
<rect class="edge-label-bg" x="155.2" y="551.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="566.0">생성 시각</text>
|
||||
<polyline class="edge kind-write style-solid emphasis-normal" points="157.0,157.0 157.0,205.0 157.0,205.0 157.0,253.0" data-evidence="419-432" />
|
||||
<rect class="edge-label-bg" x="141.8" y="191.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="206.0">티켓을 암호화한다</text>
|
||||
<rect class="edge-label-bg" x="151.9" y="191.0" width="58.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="206.0">티켓 암호화</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="157.0,324.0 157.0,372.0 157.0,372.0 157.0,420.0" data-evidence="429-438" />
|
||||
<rect class="edge-label-bg" x="141.8" y="358.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="373.0">키 이름을 만든다</text>
|
||||
<rect class="edge-label-bg" x="148.6" y="358.0" width="64.9" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="373.0">키 이름 생성</text>
|
||||
<g id="node-secret">
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-source" data-evidence="419-428" x="70.0" y="73.0" width="174.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-source" cx="157.0" cy="73.0" rx="87.0" ry="13.0" /><path class="storage-bottom" d="M 70.0 144.0 A 87.0 13.0 0 0 0 244.0 144.0" />
|
||||
<text class="node-label" x="157.0" y="100.0">k8s Secret</text>
|
||||
@@ -66,21 +66,21 @@
|
||||
<text class="node-detail" x="86.0" y="138.0">--cookie-secret 은 단수</text>
|
||||
</g>
|
||||
<g id="node-ticket">
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="429-438" x="80.5" y="253.0" width="153.0" height="71.0" rx="7" />
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="429-438" x="77.0" y="253.0" width="160.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="280.0">쿠키의 티켓</text>
|
||||
<line class="node-detail-divider" x1="94.5" y1="301.0" x2="219.5" y2="301.0" />
|
||||
<text class="node-detail" x="96.5" y="318.0">secret 을 바꾸면 못 푼다</text>
|
||||
<line class="node-detail-divider" x1="91.0" y1="301.0" x2="223.0" y2="301.0" />
|
||||
<text class="node-detail" x="93.0" y="318.0">secret 교체 시 복호화 불가</text>
|
||||
</g>
|
||||
<g id="node-redis-session">
|
||||
<rect class="node-shape kind-datastore emphasis-warning role-target" data-evidence="429-440" x="82.0" y="433.0" width="150.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-warning role-target" cx="157.0" cy="433.0" rx="75.0" ry="13.0" /><path class="storage-bottom" d="M 82.0 504.0 A 75.0 13.0 0 0 0 232.0 504.0" />
|
||||
<text class="node-label" x="157.0" y="460.0">Redis 의 세션</text>
|
||||
<line class="node-detail-divider" x1="96.0" y1="481.0" x2="218.0" y2="481.0" />
|
||||
<text class="node-detail" x="98.0" y="498.0">고아로 남는다</text>
|
||||
<text class="node-detail" x="98.0" y="498.0">고아 세션</text>
|
||||
</g>
|
||||
<g id="node-ttl">
|
||||
<rect class="node-shape kind-component emphasis-primary role-target" data-evidence="441-452" x="82.0" y="613.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="640.0">TTL</text>
|
||||
<line class="node-detail-divider" x1="96.0" y1="661.0" x2="218.0" y2="661.0" />
|
||||
<text class="node-detail" x="98.0" y="678.0">역산으로 고아를 고른다</text>
|
||||
<text class="node-detail" x="98.0" y="678.0">생성 시각 역산</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -17,6 +17,6 @@ C-1 에서 로그아웃이 다른 앱으로 퍼지지 않는 것을 관측했고
|
||||
|
||||
## Relationships
|
||||
|
||||
- **backchannelLogoutUrl → 앱의 수신 엔드포인트:** 주소가 있어야 부른다. Evidence: L458–L466.
|
||||
- **앱의 수신 엔드포인트 → 다른 앱의 세션:** 받을 곳이 있어야 지운다. Evidence: L458–L466.
|
||||
- **한 앱에서 로그아웃 → backchannelLogoutUrl:** 통지할 주소를 찾는다. Evidence: L458–L466.
|
||||
- **backchannelLogoutUrl → 앱의 수신 엔드포인트:** 호출 (주소 필요). Evidence: L458–L466.
|
||||
- **앱의 수신 엔드포인트 → 다른 앱의 세션:** 세션 삭제 (엔드포인트 필요). Evidence: L458–L466.
|
||||
- **한 앱에서 로그아웃 → backchannelLogoutUrl:** 통지 주소 조회. Evidence: L458–L466.
|
||||
|
||||
@@ -13,6 +13,6 @@ n2: "앱의 수신 엔드포인트" {
|
||||
n3: "다른 앱의 세션" {
|
||||
shape: rectangle
|
||||
}
|
||||
n0 -> n1: "통지할 주소를 찾는다"
|
||||
n1 -> n2: "주소가 있어야 부른다"
|
||||
n2 -> n3: "받을 곳이 있어야 지운다"
|
||||
n0 -> n1: "통지 주소 조회"
|
||||
n1 -> n2: "호출 (주소 필요)"
|
||||
n2 -> n3: "세션 삭제 (엔드포인트 필요)"
|
||||
|
||||
@@ -6,7 +6,7 @@ digraph techviz {
|
||||
n1 [label="backchannelLogoutUrl", shape=box, style="rounded,filled"];
|
||||
n2 [label="앱의 수신 엔드포인트", shape=box, style="rounded,filled"];
|
||||
n3 [label="다른 앱의 세션", shape=box, style="rounded,filled"];
|
||||
n0 -> n1 [label="통지할 주소를 찾는다", style=solid];
|
||||
n1 -> n2 [label="주소가 있어야 부른다", style=solid];
|
||||
n2 -> n3 [label="받을 곳이 있어야 지운다", style=solid];
|
||||
n0 -> n1 [label="통지 주소 조회", style=solid];
|
||||
n1 -> n2 [label="호출 (주소 필요)", style=solid];
|
||||
n2 -> n3 [label="세션 삭제 (엔드포인트 필요)", style=solid];
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_logout" value="한 앱에서 로그아웃" tooltip="Keycloak 세션이 끝난다. | Evidence: L458-L465" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="85.5" y="60.0" width="150.0" height="84.0" as="geometry"/>
|
||||
<mxGeometry x="82.0" y="60.0" width="150.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_kc-config" value="backchannelLogoutUrl<br/>Keycloak 은 부를 주소를 모른다" tooltip="클라이언트 설정. 비어 있었다. | Evidence: L458-L466" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="181.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_kc-config" value="backchannelLogoutUrl<br/>주소 없음" tooltip="클라이언트 설정. 비어 있었다. | Evidence: L458-L466" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="174.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_app-endpoint" value="앱의 수신 엔드포인트<br/>oidcLogout 설정 없음" tooltip="소스에 없었다. | Evidence: L458-L466" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="85.5" y="407.0" width="150.0" height="71.0" as="geometry"/>
|
||||
<mxGeometry x="82.0" y="407.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_app-session" value="다른 앱의 세션<br/>네트워크는 200 으로 닿는다" tooltip="그대로 남는다. | Evidence: L458-L466" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="85.5" y="574.0" width="150.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_app-session" value="다른 앱의 세션<br/>네트워크 도달 200" tooltip="그대로 남는다. | Evidence: L458-L466" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="82.0" y="574.0" width="150.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_c-e" value="주소가 있어야 부른다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_kc-config" target="n_app-endpoint">
|
||||
<mxCell id="e_c-e" value="호출 (주소 필요)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_kc-config" target="n_app-endpoint">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="184.5" y="359.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="359.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_e-s" value="받을 곳이 있어야 지운다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_app-endpoint" target="n_app-session">
|
||||
<mxCell id="e_e-s" value="세션 삭제 (엔드포인트 필요)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_app-endpoint" target="n_app-session">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="184.5" y="526.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="526.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_l-c" value="통지할 주소를 찾는다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_logout" target="n_kc-config">
|
||||
<mxCell id="e_l-c" value="통지 주소 조회" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_logout" target="n_kc-config">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="184.5" y="192.0" as="offset"/>
|
||||
<mxPoint x="181.0" y="192.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"id": "edge-c-e",
|
||||
"type": "arrow",
|
||||
"x": 160.5,
|
||||
"x": 157.0,
|
||||
"y": 311.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -66,7 +66,7 @@
|
||||
{
|
||||
"id": "edge-label-c-e",
|
||||
"type": "text",
|
||||
"x": 139.5,
|
||||
"x": 136.0,
|
||||
"y": 347.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -94,18 +94,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "주소가 있어야 부른다",
|
||||
"text": "호출 (주소 필요)",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "주소가 있어야 부른다",
|
||||
"originalText": "호출 (주소 필요)",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-e-s",
|
||||
"type": "arrow",
|
||||
"x": 160.5,
|
||||
"x": 157.0,
|
||||
"y": 478.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -165,9 +165,9 @@
|
||||
{
|
||||
"id": "edge-label-e-s",
|
||||
"type": "text",
|
||||
"x": 132.5,
|
||||
"x": 117.0,
|
||||
"y": 514.0,
|
||||
"width": 104,
|
||||
"width": 128,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -193,18 +193,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "받을 곳이 있어야 지운다",
|
||||
"text": "세션 삭제 (엔드포인트 필요)",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "받을 곳이 있어야 지운다",
|
||||
"originalText": "세션 삭제 (엔드포인트 필요)",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-l-c",
|
||||
"type": "arrow",
|
||||
"x": 160.5,
|
||||
"x": 157.0,
|
||||
"y": 144.0,
|
||||
"width": 0.0,
|
||||
"height": 96.0,
|
||||
@@ -264,7 +264,7 @@
|
||||
{
|
||||
"id": "edge-label-l-c",
|
||||
"type": "text",
|
||||
"x": 139.5,
|
||||
"x": 136.0,
|
||||
"y": 180.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
@@ -292,18 +292,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "통지할 주소를 찾는다",
|
||||
"text": "통지 주소 조회",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "통지할 주소를 찾는다",
|
||||
"originalText": "통지 주소 조회",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-logout",
|
||||
"type": "rectangle",
|
||||
"x": 85.5,
|
||||
"x": 82.0,
|
||||
"y": 60.0,
|
||||
"width": 150.0,
|
||||
"height": 84.0,
|
||||
@@ -333,7 +333,7 @@
|
||||
{
|
||||
"id": "node-label-logout",
|
||||
"type": "text",
|
||||
"x": 95.5,
|
||||
"x": 92.0,
|
||||
"y": 70.0,
|
||||
"width": 130.0,
|
||||
"height": 64.0,
|
||||
@@ -374,7 +374,7 @@
|
||||
"type": "rectangle",
|
||||
"x": 70.0,
|
||||
"y": 240.0,
|
||||
"width": 181.0,
|
||||
"width": 174.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -404,7 +404,7 @@
|
||||
"type": "text",
|
||||
"x": 80.0,
|
||||
"y": 250.0,
|
||||
"width": 161.0,
|
||||
"width": 154.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -430,18 +430,18 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "backchannelLogoutUrl\nKeycloak 은 부를 주소를 모른다",
|
||||
"text": "backchannelLogoutUrl\n주소 없음",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "backchannelLogoutUrl\nKeycloak 은 부를 주소를 모른다",
|
||||
"originalText": "backchannelLogoutUrl\n주소 없음",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-app-endpoint",
|
||||
"type": "rectangle",
|
||||
"x": 85.5,
|
||||
"x": 82.0,
|
||||
"y": 407.0,
|
||||
"width": 150.0,
|
||||
"height": 71.0,
|
||||
@@ -471,7 +471,7 @@
|
||||
{
|
||||
"id": "node-label-app-endpoint",
|
||||
"type": "text",
|
||||
"x": 95.5,
|
||||
"x": 92.0,
|
||||
"y": 417.0,
|
||||
"width": 130.0,
|
||||
"height": 51.0,
|
||||
@@ -510,7 +510,7 @@
|
||||
{
|
||||
"id": "node-app-session",
|
||||
"type": "rectangle",
|
||||
"x": 85.5,
|
||||
"x": 82.0,
|
||||
"y": 574.0,
|
||||
"width": 150.0,
|
||||
"height": 71.0,
|
||||
@@ -540,7 +540,7 @@
|
||||
{
|
||||
"id": "node-label-app-session",
|
||||
"type": "text",
|
||||
"x": 95.5,
|
||||
"x": 92.0,
|
||||
"y": 584.0,
|
||||
"width": 130.0,
|
||||
"height": 51.0,
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "다른 앱의 세션\n네트워크는 200 으로 닿는다",
|
||||
"text": "다른 앱의 세션\n네트워크 도달 200",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "다른 앱의 세션\n네트워크는 200 으로 닿는다",
|
||||
"originalText": "다른 앱의 세션\n네트워크 도달 200",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "c2-backchannel-both-sides",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "43396622cbf01d243efac1f48396163cc64738ef902bddda0ded0d9fb6467eb1",
|
||||
"spec_sha256": "dd700a72a2ec7d5427681b95610e9715385241a81c78e2e9dce2aafdee32b35c",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -5,8 +5,8 @@ flowchart TB
|
||||
n1["backchannelLogoutUrl"]
|
||||
n2["앱의 수신 엔드포인트"]
|
||||
n3["다른 앱의 세션"]
|
||||
n0 -->|"통지할 주소를 찾는다"| n1
|
||||
n1 -->|"주소가 있어야 부른다"| n2
|
||||
n2 -->|"받을 곳이 있어야 지운다"| n3
|
||||
n0 -->|"통지 주소 조회"| n1
|
||||
n1 -->|"호출 (주소 필요)"| n2
|
||||
n2 -->|"세션 삭제 (엔드포인트 필요)"| n3
|
||||
classDef external stroke-dasharray: 6 4
|
||||
class n0 external
|
||||
|
||||
@@ -50,35 +50,35 @@
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="690" />
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="160.5,311.0 160.5,359.0 160.5,359.0 160.5,407.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="138.7" y="345.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="184.5" y="360.0">주소가 있어야 부른다</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="160.5,478.0 160.5,526.0 160.5,526.0 160.5,574.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="131.9" y="512.0" width="105.1" height="22" rx="3" />
|
||||
<text class="edge-label" x="184.5" y="527.0">받을 곳이 있어야 지운다</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="160.5,144.0 160.5,192.0 160.5,192.0 160.5,240.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="138.7" y="178.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="184.5" y="193.0">통지할 주소를 찾는다</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="157.0,311.0 157.0,359.0 157.0,359.0 157.0,407.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="138.5" y="345.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="360.0">호출 (주소 필요)</text>
|
||||
<polyline class="edge kind-blocked style-solid emphasis-normal" points="157.0,478.0 157.0,526.0 157.0,526.0 157.0,574.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="118.4" y="512.0" width="125.2" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="527.0">세션 삭제 (엔드포인트 필요)</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="157.0,144.0 157.0,192.0 157.0,192.0 157.0,240.0" data-evidence="458-466" />
|
||||
<rect class="edge-label-bg" x="145.2" y="178.0" width="71.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="181.0" y="193.0">통지 주소 조회</text>
|
||||
<g id="node-logout">
|
||||
<g class="actor-symbol emphasis-primary" data-evidence="458-465"><circle cx="160.5" cy="80.0" r="11.0" /><line x1="160.5" y1="96.0" x2="160.5" y2="105.0" /><line x1="142.5" y1="106.0" x2="178.5" y2="106.0" /><line x1="160.5" y1="105.0" x2="145.5" y2="122.0" /><line x1="160.5" y1="105.0" x2="175.5" y2="122.0" /></g>
|
||||
<text class="node-label" x="160.5" y="137.0">한 앱에서 로그아웃</text>
|
||||
<g class="actor-symbol emphasis-primary" data-evidence="458-465"><circle cx="157.0" cy="80.0" r="11.0" /><line x1="157.0" y1="96.0" x2="157.0" y2="105.0" /><line x1="139.0" y1="106.0" x2="175.0" y2="106.0" /><line x1="157.0" y1="105.0" x2="142.0" y2="122.0" /><line x1="157.0" y1="105.0" x2="172.0" y2="122.0" /></g>
|
||||
<text class="node-label" x="157.0" y="137.0">한 앱에서 로그아웃</text>
|
||||
</g>
|
||||
<g id="node-kc-config">
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="458-466" x="70.0" y="240.0" width="181.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="160.5" y="267.0">backchannelLogoutUrl</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="288.0" x2="237.0" y2="288.0" />
|
||||
<text class="node-detail" x="86.0" y="305.0">Keycloak 은 부를 주소를 모른다</text>
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="458-466" x="70.0" y="240.0" width="174.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="267.0">backchannelLogoutUrl</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="288.0" x2="230.0" y2="288.0" />
|
||||
<text class="node-detail" x="86.0" y="305.0">주소 없음</text>
|
||||
</g>
|
||||
<g id="node-app-endpoint">
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="458-466" x="85.5" y="407.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="160.5" y="434.0">앱의 수신 엔드포인트</text>
|
||||
<line class="node-detail-divider" x1="99.5" y1="455.0" x2="221.5" y2="455.0" />
|
||||
<text class="node-detail" x="101.5" y="472.0">oidcLogout 설정 없음</text>
|
||||
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="458-466" x="82.0" y="407.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="434.0">앱의 수신 엔드포인트</text>
|
||||
<line class="node-detail-divider" x1="96.0" y1="455.0" x2="218.0" y2="455.0" />
|
||||
<text class="node-detail" x="98.0" y="472.0">oidcLogout 설정 없음</text>
|
||||
</g>
|
||||
<g id="node-app-session">
|
||||
<rect class="node-shape kind-component emphasis-warning role-target" data-evidence="458-466" x="85.5" y="574.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="160.5" y="601.0">다른 앱의 세션</text>
|
||||
<line class="node-detail-divider" x1="99.5" y1="622.0" x2="221.5" y2="622.0" />
|
||||
<text class="node-detail" x="101.5" y="639.0">네트워크는 200 으로 닿는다</text>
|
||||
<rect class="node-shape kind-component emphasis-warning role-target" data-evidence="458-466" x="82.0" y="574.0" width="150.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="157.0" y="601.0">다른 앱의 세션</text>
|
||||
<line class="node-detail-divider" x1="96.0" y1="622.0" x2="218.0" y2="622.0" />
|
||||
<text class="node-detail" x="98.0" y="639.0">네트워크 도달 200</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -17,6 +17,6 @@ volatile 모드에서 로그인은 SQL 을 0개 쏜다. refresh 는 딱 한 문
|
||||
|
||||
## Relationships
|
||||
|
||||
- **CLIENT 조회 → CLIENT_SCOPE_CLIENT 조회:** refresh 는 스코프도 다시 계산한다. Evidence: L284–L292.
|
||||
- **CLIENT 조회 → CLIENT_SCOPE_CLIENT 조회:** 스코프 재계산. Evidence: L284–L292.
|
||||
- **로그인 · refresh 요청 → CLIENT 조회:** 클라이언트 확인. Evidence: L306–L312.
|
||||
- **CLIENT_SCOPE_CLIENT 조회 → PostgreSQL:** 캐시에 없으면 여기까지 간다. Evidence: L296–L302.
|
||||
- **CLIENT_SCOPE_CLIENT 조회 → PostgreSQL:** 캐시 미스. Evidence: L296–L302.
|
||||
|
||||
@@ -14,5 +14,5 @@ n3: "PostgreSQL" {
|
||||
shape: cylinder
|
||||
}
|
||||
n0 -> n1: "클라이언트 확인"
|
||||
n1 -> n2: "refresh 는 스코프도 다시 계산한다"
|
||||
n2 -> n3: "캐시에 없으면 여기까지 간다"
|
||||
n1 -> n2: "스코프 재계산"
|
||||
n2 -> n3: "캐시 미스"
|
||||
|
||||
@@ -7,6 +7,6 @@ digraph techviz {
|
||||
n2 [label="CLIENT_SCOPE_CLIENT 조회", shape=box, style="rounded,filled"];
|
||||
n3 [label="PostgreSQL", shape=cylinder, style="rounded,filled"];
|
||||
n0 -> n1 [label="클라이언트 확인", style=solid];
|
||||
n1 -> n2 [label="refresh 는 스코프도 다시 계산한다", style=solid];
|
||||
n2 -> n3 [label="캐시에 없으면 여기까지 간다", style=solid];
|
||||
n1 -> n2 [label="스코프 재계산", style=solid];
|
||||
n2 -> n3 [label="캐시 미스", style=solid];
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<mxCell id="n_client-lookup" value="CLIENT 조회<br/>select ce1_0.ID from CLIENT" tooltip="냉시동에서 여기서 실패한다. | Evidence: L306-L312" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="240.0" width="223.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_scope-lookup" value="CLIENT_SCOPE_CLIENT 조회<br/>DEFAULT_SCOPE='f' — 선택적 스코프" tooltip="refresh 만 쏘고 첫 번째만 쏜다. | Evidence: L284-L292" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="407.0" width="223.0" height="71.0" as="geometry"/>
|
||||
<mxCell id="n_scope-lookup" value="CLIENT_SCOPE_CLIENT 조회<br/>DEFAULT_SCOPE='f'" tooltip="refresh 만 쏘고 첫 번째만 쏜다. | Evidence: L284-L292" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="87.5" y="407.0" width="188.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_db" value="PostgreSQL<br/>캐시에 있으면 닿지 않는다" tooltip="세운 상태다. 여기 닿는 조회만 실패한다. | Evidence: L296-L302" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_db" value="PostgreSQL<br/>캐시 미스 시에만 도달" tooltip="세운 상태다. 여기 닿는 조회만 실패한다. | Evidence: L296-L302" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="106.5" y="574.0" width="150.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_c-s" value="refresh 는 스코프도 다시 계산한다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client-lookup" target="n_scope-lookup">
|
||||
<mxCell id="e_c-s" value="스코프 재계산" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_client-lookup" target="n_scope-lookup">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="205.5" y="359.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
@@ -27,7 +27,7 @@
|
||||
<mxPoint x="205.5" y="192.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_s-db" value="캐시에 없으면 여기까지 간다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_scope-lookup" target="n_db">
|
||||
<mxCell id="e_s-db" value="캐시 미스" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_scope-lookup" target="n_db">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="205.5" y="526.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
{
|
||||
"id": "edge-label-c-s",
|
||||
"type": "text",
|
||||
"x": 117.5,
|
||||
"x": 160.5,
|
||||
"y": 347.0,
|
||||
"width": 176,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -94,11 +94,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "refresh 는 스코프도 다시 계산한다",
|
||||
"text": "스코프 재계산",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "refresh 는 스코프도 다시 계산한다",
|
||||
"originalText": "스코프 재계산",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -264,9 +264,9 @@
|
||||
{
|
||||
"id": "edge-label-s-db",
|
||||
"type": "text",
|
||||
"x": 145.5,
|
||||
"x": 160.5,
|
||||
"y": 514.0,
|
||||
"width": 120,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -292,11 +292,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "캐시에 없으면 여기까지 간다",
|
||||
"text": "캐시 미스",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "캐시에 없으면 여기까지 간다",
|
||||
"originalText": "캐시 미스",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -441,9 +441,9 @@
|
||||
{
|
||||
"id": "node-scope-lookup",
|
||||
"type": "rectangle",
|
||||
"x": 70.0,
|
||||
"x": 87.5,
|
||||
"y": 407.0,
|
||||
"width": 223.0,
|
||||
"width": 188.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -471,9 +471,9 @@
|
||||
{
|
||||
"id": "node-label-scope-lookup",
|
||||
"type": "text",
|
||||
"x": 80.0,
|
||||
"x": 97.5,
|
||||
"y": 417.0,
|
||||
"width": 203.0,
|
||||
"width": 168.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -499,11 +499,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "CLIENT_SCOPE_CLIENT 조회\nDEFAULT_SCOPE='f' — 선택적 스코프",
|
||||
"text": "CLIENT_SCOPE_CLIENT 조회\nDEFAULT_SCOPE='f'",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "CLIENT_SCOPE_CLIENT 조회\nDEFAULT_SCOPE='f' — 선택적 스코프",
|
||||
"originalText": "CLIENT_SCOPE_CLIENT 조회\nDEFAULT_SCOPE='f'",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
@@ -568,11 +568,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "PostgreSQL\n캐시에 있으면 닿지 않는다",
|
||||
"text": "PostgreSQL\n캐시 미스 시에만 도달",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "PostgreSQL\n캐시에 있으면 닿지 않는다",
|
||||
"originalText": "PostgreSQL\n캐시 미스 시에만 도달",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "cache-temperature-outcomes",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "d29d1507f8c0801290e71152181fc3427617ae85cd3f1d72493352841cb60224",
|
||||
"spec_sha256": "ef12517d7e1783c23b34a19ae285946eaf73ec600e5487c5d9bca1c086e0c22d",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak-session-store/final/document.md",
|
||||
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
|
||||
|
||||
@@ -6,7 +6,7 @@ flowchart TB
|
||||
n2["CLIENT_SCOPE_CLIENT 조회"]
|
||||
n3[("PostgreSQL")]
|
||||
n0 -->|"클라이언트 확인"| n1
|
||||
n1 -->|"refresh 는 스코프도 다시 계산한다"| n2
|
||||
n2 -->|"캐시에 없으면 여기까지 간다"| n3
|
||||
n1 -->|"스코프 재계산"| n2
|
||||
n2 -->|"캐시 미스"| n3
|
||||
classDef external stroke-dasharray: 6 4
|
||||
class n0 external
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
</defs>
|
||||
<rect class="canvas" width="680" height="716" />
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="181.5,311.0 181.5,359.0 181.5,359.0 181.5,407.0" data-evidence="284-292" />
|
||||
<rect class="edge-label-bg" x="122.8" y="345.0" width="165.4" height="22" rx="3" />
|
||||
<text class="edge-label" x="205.5" y="360.0">refresh 는 스코프도 다시 계산한다</text>
|
||||
<rect class="edge-label-bg" x="173.1" y="345.0" width="64.9" height="22" rx="3" />
|
||||
<text class="edge-label" x="205.5" y="360.0">스코프 재계산</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="181.5,144.0 181.5,192.0 181.5,192.0 181.5,240.0" data-evidence="306-312" />
|
||||
<rect class="edge-label-bg" x="169.7" y="178.0" width="71.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="205.5" y="193.0">클라이언트 확인</text>
|
||||
<polyline class="edge kind-read style-solid emphasis-normal" points="181.5,478.0 181.5,526.0 181.5,526.0 181.5,574.0" data-evidence="296-302" />
|
||||
<rect class="edge-label-bg" x="146.2" y="512.0" width="118.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="205.5" y="527.0">캐시에 없으면 여기까지 간다</text>
|
||||
<rect class="edge-label-bg" x="179.8" y="512.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="205.5" y="527.0">캐시 미스</text>
|
||||
<g id="node-request">
|
||||
<g class="actor-symbol emphasis-primary" data-evidence="284-296"><circle cx="181.5" cy="80.0" r="11.0" /><line x1="181.5" y1="96.0" x2="181.5" y2="105.0" /><line x1="163.5" y1="106.0" x2="199.5" y2="106.0" /><line x1="181.5" y1="105.0" x2="166.5" y2="122.0" /><line x1="181.5" y1="105.0" x2="196.5" y2="122.0" /></g>
|
||||
<text class="node-label" x="181.5" y="137.0">로그인 · refresh 요청</text>
|
||||
@@ -70,15 +70,15 @@
|
||||
<text class="node-detail" x="86.0" y="305.0">select ce1_0.ID from CLIENT</text>
|
||||
</g>
|
||||
<g id="node-scope-lookup">
|
||||
<rect class="node-shape kind-process emphasis-warning role-control" data-evidence="284-292" x="70.0" y="407.0" width="223.0" height="71.0" rx="7" />
|
||||
<rect class="node-shape kind-process emphasis-warning role-control" data-evidence="284-292" x="87.5" y="407.0" width="188.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="181.5" y="434.0">CLIENT_SCOPE_CLIENT 조회</text>
|
||||
<line class="node-detail-divider" x1="84.0" y1="455.0" x2="279.0" y2="455.0" />
|
||||
<text class="node-detail" x="86.0" y="472.0">DEFAULT_SCOPE='f' — 선택적 스코프</text>
|
||||
<line class="node-detail-divider" x1="101.5" y1="455.0" x2="261.5" y2="455.0" />
|
||||
<text class="node-detail" x="103.5" y="472.0">DEFAULT_SCOPE='f'</text>
|
||||
</g>
|
||||
<g id="node-db">
|
||||
<rect class="node-shape kind-datastore emphasis-primary role-target" data-evidence="296-302" x="106.5" y="587.0" width="150.0" height="71.0" /><ellipse class="node-shape kind-datastore emphasis-primary role-target" cx="181.5" cy="587.0" rx="75.0" ry="13.0" /><path class="storage-bottom" d="M 106.5 658.0 A 75.0 13.0 0 0 0 256.5 658.0" />
|
||||
<text class="node-label" x="181.5" y="614.0">PostgreSQL</text>
|
||||
<line class="node-detail-divider" x1="120.5" y1="635.0" x2="242.5" y2="635.0" />
|
||||
<text class="node-detail" x="122.5" y="652.0">캐시에 있으면 닿지 않는다</text>
|
||||
<text class="node-detail" x="122.5" y="652.0">캐시 미스 시에만 도달</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.2 KiB |
@@ -18,7 +18,7 @@
|
||||
|
||||
## Relationships
|
||||
|
||||
- **Liquibase 검증 → databasechangelog 행 수:** 무엇을 보고 판단하나. Evidence: L499–L505.
|
||||
- **Liquibase 검증 → StatefulSet 롤링 업데이트:** 실패가 여기서 멈춘다. Evidence: L492–L497.
|
||||
- **Liquibase 검증 → databasechangelog 행 수:** 판단 기준. Evidence: L499–L505.
|
||||
- **Liquibase 검증 → StatefulSet 롤링 업데이트:** 중단 지점. Evidence: L492–L497.
|
||||
- **옛 버전으로 되돌리기 → Liquibase 검증:** 기동 시 검증. Evidence: L483–L491.
|
||||
- **StatefulSet 롤링 업데이트 → 외부 서비스:** 남은 파드가 응답한다. Evidence: L492–L498.
|
||||
- **StatefulSet 롤링 업데이트 → 외부 서비스:** 잔여 파드 응답. Evidence: L492–L498.
|
||||
|
||||
@@ -17,6 +17,6 @@ n4: "databasechangelog 행 수" {
|
||||
shape: cylinder
|
||||
}
|
||||
n0 -> n1: "기동 시 검증"
|
||||
n1 -> n2: "실패가 여기서 멈춘다"
|
||||
n2 -> n3: "남은 파드가 응답한다"
|
||||
n1 -> n4: "무엇을 보고 판단하나"
|
||||
n1 -> n2: "중단 지점"
|
||||
n2 -> n3: "잔여 파드 응답"
|
||||
n1 -> n4: "판단 기준"
|
||||
|
||||
@@ -8,7 +8,7 @@ digraph techviz {
|
||||
n3 [label="외부 서비스", shape=box, style="rounded,filled"];
|
||||
n4 [label="databasechangelog 행 수", shape=cylinder, style="rounded,filled"];
|
||||
n0 -> n1 [label="기동 시 검증", style=solid];
|
||||
n1 -> n2 [label="실패가 여기서 멈춘다", style=solid];
|
||||
n2 -> n3 [label="남은 파드가 응답한다", style=solid];
|
||||
n1 -> n4 [label="무엇을 보고 판단하나", style=solid];
|
||||
n1 -> n2 [label="중단 지점", style=solid];
|
||||
n2 -> n3 [label="잔여 파드 응답", style=solid];
|
||||
n1 -> n4 [label="판단 기준", style=solid];
|
||||
}
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
<mxCell id="n_liquibase" value="Liquibase 검증<br/>ValidationFailedException: 1 changesets check sum" tooltip="새 버전이 남긴 체크섬을 거부한다. | Evidence: L483-L491" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#d97706;fillColor=#fffdf5;" vertex="1" parent="1">
|
||||
<mxGeometry x="124.0" y="220.0" width="300.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_changelog" value="databasechangelog 행 수<br/>늘었으면 스키마가 움직였다" tooltip="전후로 같으면 롤백된다. | Evidence: L499-L505" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_changelog" value="databasechangelog 행 수<br/>전후 행 수 비교" tooltip="전후로 같으면 롤백된다. | Evidence: L499-L505" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=cylinder3;boundedLbl=1;backgroundOutline=1;fillColor=#eef6fb;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="387.0" width="181.0" height="97.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_rolling" value="StatefulSet 롤링 업데이트<br/>나머지 파드는 건드리지 않는다" tooltip="첫 파드가 실패하면 거기서 멈춘다. | Evidence: L492-L497" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxCell id="n_rolling" value="StatefulSet 롤링 업데이트<br/>나머지 파드 유지" tooltip="첫 파드가 실패하면 거기서 멈춘다. | Evidence: L492-L497" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="311.0" y="400.0" width="167.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_service" value="외부 서비스" tooltip="남은 파드가 계속 200 을 낸다. | Evidence: L492-L498" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="199.0" y="580.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_l-cl" value="무엇을 보고 판단하나" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_liquibase" target="n_changelog">
|
||||
<mxCell id="e_l-cl" value="판단 기준" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_liquibase" target="n_changelog">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="212.8" y="311.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_l-ro" value="실패가 여기서 멈춘다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_liquibase" target="n_rolling">
|
||||
<mxCell id="e_l-ro" value="중단 지점" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_liquibase" target="n_rolling">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="338.8" y="317.5" as="offset"/>
|
||||
</mxGeometry>
|
||||
@@ -35,7 +35,7 @@
|
||||
<mxPoint x="298.0" y="172.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_ro-s" value="남은 파드가 응답한다" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_rolling" target="n_service">
|
||||
<mxCell id="e_ro-s" value="잔여 파드 응답" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_rolling" target="n_service">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="334.2" y="497.5" as="offset"/>
|
||||
</mxGeometry>
|
||||
|
||||