refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
@@ -6,17 +6,17 @@
## Long description
oauth2-proxy 는 세션 전체 쿠키에 담고 replica 같은 k8s Secret 을 읽을 뿐이다. 공유할 서버 상태가 없으니 콜백이 다른 replica 로 가도 된다. 대신 --cookie-secret 이 단수라 옛 secret 도 당분간 받아준다가 불가능하고 교체하는 순간 모든 쿠키가 한꺼번에 무효가 된다. Redis 저장소를 켜면 쿠키에는 티켓만 남는데, 티켓 안에 세션 id 가 있으므로 secret 을 바꾸면 어느 Redis 키를 지울지도 모르게 된다.
cookie-only 모드에서는 세션 전체 쿠키에 있어 replica 같은 secret만 읽으면 된다. Redis session store를 켜면 쿠키에는 ticket만 남고 실제 session은 Redis에 생긴다. secret을 바꾸면 ticket을 풀 수 없어 어느 Redis key를 지울지 알 수 없고 고아 session이 남는다. refresh:disabled에서는 TTL이 생성 시각의 함수라 회전 시각과 비교해 고아를 골라낼 수 있지만 --cookie-refresh를 켜면 이 역산은 성립하지 않는다.
## Elements and evidence
- **k8s Secret** (datastore): 모든 replica 가 같은 값을 읽는다. Evidence: L419L428.
- **쿠키의 티켓** (component): 세션 id 와 복호화 키가 함께 암호화되어 있다. Evidence: L429L438.
- **Redis 의 세션** (datastore): 티켓을 못 풀면 어느 키인지도 모른다. Evidence: L429L440.
- **TTL** (component): 요청으로 갱신되지 않아 생성 시각의 함수다. Evidence: L441L452.
- **k8s Secret** (datastore): 모든 replica 가 같은 값을 읽는다. Evidence: L863L867.
- **쿠키의 티켓** (component): 세션 id 와 복호화 키가 함께 암호화되어 있다. Evidence: L923L932.
- **Redis 의 세션** (datastore): 티켓을 못 풀면 어느 키인지도 모른다. Evidence: L923L932.
- **TTL** (component): 요청으로 갱신되지 않아 생성 시각의 함수다. Evidence: L935L946.
## Relationships
- **Redis 의 세션 → TTL:** 생성 시각. Evidence: L441L452.
- **k8s Secret → 쿠키의 티켓:** 티켓 암호화. Evidence: L419L432.
- **쿠키의 티켓 → Redis 의 세션:** 키 이름 생성. Evidence: L429L438.
- **Redis 의 세션 → TTL:** 생성 시각. Evidence: L935L946.
- **k8s Secret → 쿠키의 티켓:** 티켓 암호화. Evidence: L919L925.
- **쿠키의 티켓 → Redis 의 세션:** 키 이름 생성. Evidence: L923L932.
@@ -1,35 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-07-23T00:00:00.000Z" agent="techviz-harness" version="24.7.17" type="device">
<diagram id="b7-cookie-session-tradeoff" name="쿠키에 담으면 공유할 것이 없다">
<mxGraphModel dx="680" dy="729" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<mxGraphModel dx="680" dy="1225" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1225" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="n_secret" value="k8s Secret&lt;br/&gt;--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 id="n_secret" value="k8s Secret&lt;br/&gt;--cookie-secret 은 단수" tooltip="모든 replica 가 같은 값을 읽는다. | Evidence: L863-L867" 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="35.0" y="145.0" width="174.0" height="71.0" as="geometry"/>
</mxCell>
<mxCell id="n_ticket" value="쿠키의 티켓&lt;br/&gt;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 id="n_ticket" value="쿠키의 티켓&lt;br/&gt;secret 교체 시 복호화 불가" tooltip="세션 id 와 복호화 키가 함께 암호화되어 있다. | Evidence: L923-L932" 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="35.0" y="479.0" width="160.0" height="71.0" as="geometry"/>
</mxCell>
<mxCell id="n_redis-session" value="Redis 의 세션&lt;br/&gt;고아 세션" 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 id="n_redis-session" value="Redis 의 세션&lt;br/&gt;고아 세션" tooltip="티켓을 못 풀면 어느 키인지도 모른다. | Evidence: L923-L932" 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="35.0" y="799.0" width="150.0" height="71.0" as="geometry"/>
</mxCell>
<mxCell id="n_ttl" value="TTL&lt;br/&gt;생성 시각 역산" 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 id="n_ttl" value="TTL&lt;br/&gt;생성 시각 역산" tooltip="요청으로 갱신되지 않아 생성 시각의 함수다. | Evidence: L935-L946" 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="35.0" y="1109.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">
<mxGeometry relative="1" as="geometry">
<mxPoint x="181.0" y="565.0" as="offset"/>
<mxPoint x="134.0" y="989.5" 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">
<mxGeometry relative="1" as="geometry">
<mxPoint x="181.0" y="205.0" as="offset"/>
<mxPoint x="118.5" y="319.5" 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">
<mxGeometry relative="1" as="geometry">
<mxPoint x="181.0" y="372.0" as="offset"/>
<mxPoint x="112.5" y="646.5" as="offset"/>
</mxGeometry>
</mxCell>
</root>
@@ -6,10 +6,10 @@
{
"id": "edge-r-ttl",
"type": "arrow",
"x": 157.0,
"y": 517.0,
"x": 110.0,
"y": 870.0,
"width": 0.0,
"height": 96.0,
"height": 239.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
@@ -37,15 +37,15 @@
],
[
0.0,
48.0
119.5
],
[
0.0,
48.0
119.5
],
[
0.0,
96.0
239.0
]
],
"lastCommittedPoint": null,
@@ -66,8 +66,8 @@
{
"id": "edge-label-r-ttl",
"type": "text",
"x": 136.0,
"y": 553.0,
"x": 89.0,
"y": 977.5,
"width": 90,
"height": 24,
"angle": 0,
@@ -105,10 +105,10 @@
{
"id": "edge-s-t",
"type": "arrow",
"x": 157.0,
"y": 157.0,
"width": 0.0,
"height": 96.0,
"x": 115.0,
"y": 216.0,
"width": 7.0,
"height": 263.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
@@ -131,20 +131,20 @@
"locked": false,
"points": [
[
0.0,
7.0,
0.0
],
[
0.0,
48.0
7.0,
131.5
],
[
0.0,
48.0
131.5
],
[
0.0,
96.0
263.0
]
],
"lastCommittedPoint": null,
@@ -165,8 +165,8 @@
{
"id": "edge-label-s-t",
"type": "text",
"x": 136.0,
"y": 193.0,
"x": 73.5,
"y": 307.5,
"width": 90,
"height": 24,
"angle": 0,
@@ -204,10 +204,10 @@
{
"id": "edge-t-r",
"type": "arrow",
"x": 157.0,
"y": 324.0,
"width": 0.0,
"height": 96.0,
"x": 110.0,
"y": 550.0,
"width": 5.0,
"height": 249.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
@@ -230,20 +230,20 @@
"locked": false,
"points": [
[
0.0,
5.0,
0.0
],
[
0.0,
48.0
5.0,
124.5
],
[
0.0,
48.0
124.5
],
[
0.0,
96.0
249.0
]
],
"lastCommittedPoint": null,
@@ -264,8 +264,8 @@
{
"id": "edge-label-t-r",
"type": "text",
"x": 136.0,
"y": 360.0,
"x": 67.5,
"y": 634.5,
"width": 90,
"height": 24,
"angle": 0,
@@ -303,10 +303,10 @@
{
"id": "node-secret",
"type": "rectangle",
"x": 70.0,
"y": 60.0,
"x": 35.0,
"y": 145.0,
"width": 174.0,
"height": 97.0,
"height": 71.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "#e7f5ff",
@@ -333,10 +333,10 @@
{
"id": "node-label-secret",
"type": "text",
"x": 80.0,
"y": 70.0,
"x": 45.0,
"y": 155.0,
"width": 154.0,
"height": 77.0,
"height": 51.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
@@ -372,8 +372,8 @@
{
"id": "node-ticket",
"type": "rectangle",
"x": 77.0,
"y": 253.0,
"x": 35.0,
"y": 479.0,
"width": 160.0,
"height": 71.0,
"angle": 0,
@@ -402,8 +402,8 @@
{
"id": "node-label-ticket",
"type": "text",
"x": 87.0,
"y": 263.0,
"x": 45.0,
"y": 489.0,
"width": 140.0,
"height": 51.0,
"angle": 0,
@@ -441,10 +441,10 @@
{
"id": "node-redis-session",
"type": "rectangle",
"x": 82.0,
"y": 420.0,
"x": 35.0,
"y": 799.0,
"width": 150.0,
"height": 97.0,
"height": 71.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "#e7f5ff",
@@ -471,10 +471,10 @@
{
"id": "node-label-redis-session",
"type": "text",
"x": 92.0,
"y": 430.0,
"x": 45.0,
"y": 809.0,
"width": 130.0,
"height": 77.0,
"height": 51.0,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
@@ -510,8 +510,8 @@
{
"id": "node-ttl",
"type": "rectangle",
"x": 82.0,
"y": 613.0,
"x": 35.0,
"y": 1109.0,
"width": 150.0,
"height": 71.0,
"angle": 0,
@@ -540,8 +540,8 @@
{
"id": "node-label-ttl",
"type": "text",
"x": 92.0,
"y": 623.0,
"x": 45.0,
"y": 1119.0,
"width": 130.0,
"height": 51.0,
"angle": 0,
@@ -2,14 +2,14 @@
"harness_version": "0.2.0",
"spec_id": "b7-cookie-session-tradeoff",
"spec_version": "1.1",
"spec_sha256": "9a594212157672a9188e296e73a0ab9af3d53992c94afdbfe2e1aeedaf8998bc",
"spec_sha256": "27651564d83168008bdeef9aa1782631988abfbbaeffa80073aa3b854f237bf9",
"source_context": {
"document": "docs/keycloak-session-store/final/document.md",
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
"document_sha256": "28aef96a2bbb94fbb10ade26a71238fee62a5a4d9fa6e7749ae98cfd0a65e560",
"anchor": {
"kind": "heading",
"value": "B-7 · B-7a — 쿠키에 담는 세션, 그리고 그 대가",
"line": 424
"line": 884
}
},
"outputs": [
@@ -21,7 +21,7 @@
"b7-cookie-session-tradeoff.excalidraw",
"b7-cookie-session-tradeoff.alt.md"
],
"lint_issue_count": 0,
"lint_issue_count": 1,
"assumption_count": 0,
"assumptions_allowed": false,
"composition_profile": "component-flow",
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="729" viewBox="0 0 680 729" role="img" aria-labelledby="diagram-title diagram-description">
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="1225" viewBox="0 0 680 1225" role="img" aria-labelledby="diagram-title diagram-description">
<title id="diagram-title">쿠키에 담으면 공유할 것이 없다</title>
<desc id="diagram-description">oauth2-proxy 는 세션 전체 쿠키에 담고 replica 같은 k8s Secret 을 읽을 뿐이다. 공유할 서버 상태가 없으니 콜백이 다른 replica 로 가도 된다. 대신 --cookie-secret 이 단수라 옛 secret 도 당분간 받아준다가 불가능하고 교체하는 순간 모든 쿠키가 한꺼번에 무효가 된다. Redis 저장소를 켜면 쿠키에는 티켓만 남는데, 티켓 안에 세션 id 가 있으므로 secret 을 바꾸면 어느 Redis 키를 지울지도 모르게 된다.</desc>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;b7-cookie-session-tradeoff&quot;,&quot;profile&quot;:&quot;component-flow&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;docs/keycloak-session-store/final/document.md&quot;,&quot;document_sha256&quot;:&quot;1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;heading&quot;,&quot;value&quot;:&quot;B-7 · B-7a — 쿠키에 담는 세션, 그리고 그 대가&quot;,&quot;line&quot;:424}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<desc id="diagram-description">cookie-only 모드에서는 세션 전체 쿠키에 있어 replica 같은 secret만 읽으면 된다. Redis session store를 켜면 쿠키에는 ticket만 남고 실제 session은 Redis에 생긴다. secret을 바꾸면 ticket을 풀 수 없어 어느 Redis key를 지울지 알 수 없고 고아 session이 남는다. refresh:disabled에서는 TTL이 생성 시각의 함수라 회전 시각과 비교해 고아를 골라낼 수 있지만 --cookie-refresh를 켜면 이 역산은 성립하지 않는다.</desc>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;b7-cookie-session-tradeoff&quot;,&quot;profile&quot;:&quot;component-flow&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;docs/keycloak-session-store/final/document.md&quot;,&quot;document_sha256&quot;:&quot;28aef96a2bbb94fbb10ade26a71238fee62a5a4d9fa6e7749ae98cfd0a65e560&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;heading&quot;,&quot;value&quot;:&quot;B-7 · B-7a — 쿠키에 담는 세션, 그리고 그 대가&quot;,&quot;line&quot;:884}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
@@ -49,38 +49,38 @@
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
</style>
</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="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="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="148.6" y="358.0" width="64.9" height="22" rx="3" />
<text class="edge-label" x="181.0" y="373.0">키 이름 생성</text>
<rect class="canvas" width="680" height="1225" />
<polyline class="edge kind-read style-solid emphasis-normal" points="110.0,870.0 110.0,989.5 110.0,989.5 110.0,1109.0" data-evidence="935-946" />
<rect class="edge-label-bg" x="108.2" y="975.5" width="51.5" height="22" rx="3" />
<text class="edge-label" x="134.0" y="990.5">생성 시각</text>
<polyline class="edge kind-write style-solid emphasis-normal" points="122.0,216.0 122.0,347.5 115.0,347.5 115.0,479.0" data-evidence="919-925" />
<rect class="edge-label-bg" x="89.4" y="305.5" width="58.2" height="22" rx="3" />
<text class="edge-label" x="118.5" y="320.5">티켓 암호화</text>
<polyline class="edge kind-read style-solid emphasis-normal" points="115.0,550.0 115.0,674.5 110.0,674.5 110.0,799.0" data-evidence="923-932" />
<rect class="edge-label-bg" x="80.0" y="632.5" width="64.9" height="22" rx="3" />
<text class="edge-label" x="112.5" y="647.5">키 이름 생성</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>
<line class="node-detail-divider" x1="84.0" y1="121.0" x2="230.0" y2="121.0" />
<text class="node-detail" x="86.0" y="138.0">--cookie-secret 은 단수</text>
<rect class="node-shape kind-datastore emphasis-primary role-source" data-evidence="863-867" x="35.0" y="156.8" width="174.0" height="47.3" /><ellipse class="node-shape kind-datastore emphasis-primary role-source" cx="122.0" cy="156.8" rx="87.0" ry="11.8" /><path class="storage-bottom" d="M 35.0 204.2 A 87.0 11.8 0 0 0 209.0 204.2" />
<text class="node-label" x="122.0" y="172.0">k8s Secret</text>
<line class="node-detail-divider" x1="49.0" y1="193.0" x2="195.0" y2="193.0" />
<text class="node-detail" x="51.0" y="210.0">--cookie-secret 은 단수</text>
</g>
<g id="node-ticket">
<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="91.0" y1="301.0" x2="223.0" y2="301.0" />
<text class="node-detail" x="93.0" y="318.0">secret 교체 시 복호화 불가</text>
<rect class="node-shape kind-component emphasis-warning role-control" data-evidence="923-932" x="35.0" y="479.0" width="160.0" height="71.0" rx="7" />
<text class="node-label" x="115.0" y="506.0">쿠키의 티켓</text>
<line class="node-detail-divider" x1="49.0" y1="527.0" x2="181.0" y2="527.0" />
<text class="node-detail" x="51.0" y="544.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>
<rect class="node-shape kind-datastore emphasis-warning role-target" data-evidence="923-932" x="35.0" y="810.8" width="150.0" height="47.3" /><ellipse class="node-shape kind-datastore emphasis-warning role-target" cx="110.0" cy="810.8" rx="75.0" ry="11.8" /><path class="storage-bottom" d="M 35.0 858.2 A 75.0 11.8 0 0 0 185.0 858.2" />
<text class="node-label" x="110.0" y="826.0">Redis 의 세션</text>
<line class="node-detail-divider" x1="49.0" y1="847.0" x2="171.0" y2="847.0" />
<text class="node-detail" x="51.0" y="864.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>
<rect class="node-shape kind-component emphasis-primary role-target" data-evidence="935-946" x="35.0" y="1109.0" width="150.0" height="71.0" rx="7" />
<text class="node-label" x="110.0" y="1136.0">TTL</text>
<line class="node-detail-divider" x1="49.0" y1="1157.0" x2="171.0" y2="1157.0" />
<text class="node-detail" x="51.0" y="1174.0">생성 시각 역산</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB