설계 개편
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
digraph techviz {
|
||||
graph [rankdir=LR, splines=ortho, nodesep=0.55, ranksep=0.85, label="승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다", labelloc=t, fontsize=20];
|
||||
graph [rankdir=LR, splines=ortho, nodesep=0.55, ranksep=0.85];
|
||||
node [fontname=Helvetica, fontsize=11, margin="0.18,0.12", style="rounded,filled", fillcolor=white, color="#2d4357", penwidth=1.5];
|
||||
edge [fontname=Helvetica, fontsize=10, color="#364b5f", penwidth=1.4, arrowsize=0.75];
|
||||
n0 [label="클라이언트", shape=box, style="rounded,dashed,filled"];
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
<?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="payment-request" name="승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다">
|
||||
<mxGraphModel dx="1214" dy="587" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1214" pageHeight="1169" math="0" shadow="0">
|
||||
<mxGraphModel dx="1198" dy="487" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1198" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="n_client" value="클라이언트" tooltip="로그인 세션과 장바구니 식별자를 가지고 결제를 요청한다. | Evidence: L7-L7, L11-L11" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;dashed=1;fillColor=#f5f7fa;" vertex="1" parent="1">
|
||||
<mxGeometry x="70.0" y="281.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="70.0" y="186.0" width="150.0" height="84.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_auth-gateway" value="인증 게이트웨이" tooltip="세션을 검증하고 유효한 요청만 체크아웃 API로 전달한다. | Evidence: L7-L7, L11-L11" 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="380.0" y="281.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="380.0" y="196.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_checkout-api" value="체크아웃 API" tooltip="주문 상태를 저장하고 결제 승인 및 이벤트 발행을 조정한다. | Evidence: L7-L7, L11-L13" 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="690.0" y="281.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxCell id="n_checkout-api" value="체크아웃 API" tooltip="주문 상태를 저장하고 결제 승인 및 이벤트 발행을 조정한다. | Evidence: L7-L7, L11-L13" 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="690.0" y="196.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_event-bus" value="이벤트 버스" tooltip="승인된 결제를 payment.approved 이벤트로 수신한다. | Evidence: L13-L13" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;rounded=1;arcSize=50;fillColor=#f6f1fb;" vertex="1" parent="1">
|
||||
<mxGeometry x="1002.2" y="145.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="1001.5" y="60.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_orders-db" value="PostgreSQL 주문 저장소" tooltip="주문을 PENDING으로 기록하고 승인 후 PAID로 갱신한다. | Evidence: L13-L13" 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;" vertex="1" parent="1">
|
||||
<mxGeometry x="1000.0" y="281.0" width="154.4" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="1000.0" y="196.0" width="153.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_payment-provider" value="결제 제공자 API" tooltip="체크아웃 API의 결제 승인 요청을 처리하고 승인 응답을 반환한다. | Evidence: L13-L13" 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="1002.2" y="417.0" width="150.0" height="64.0" as="geometry"/>
|
||||
<mxGeometry x="1001.5" y="332.0" width="150.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_authorization-approved" value="승인 응답" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_payment-provider" target="n_checkout-api">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="853.1" y="499.0" as="offset"/>
|
||||
<mxPoint x="852.8" y="414.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_authorization-request" value="승인 요청" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_checkout-api" target="n_payment-provider">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="907.1" y="385.4" as="offset"/>
|
||||
<mxPoint x="906.8" y="300.4" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_client-request" value="HTTPS 결제 요청" 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_auth-gateway">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="300.0" y="285.0" as="offset"/>
|
||||
<mxPoint x="300.0" y="200.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_create-pending" value="PENDING 주문 기록" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_checkout-api" target="n_orders-db">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="944.0" y="303.5" as="offset"/>
|
||||
<mxPoint x="944.0" y="218.5" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_mark-paid" value="PAID 상태 갱신" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_checkout-api" target="n_orders-db">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="924.5" y="341.0" as="offset"/>
|
||||
<mxPoint x="924.5" y="256.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_publish-approved" value="payment.approved 발행" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;dashed=1;" edge="1" parent="1" source="n_checkout-api" target="n_event-bus">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="945.1" y="235.1" as="offset"/>
|
||||
<mxPoint x="944.8" y="150.1" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_validated-request" value="검증된 요청 전달" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_auth-gateway" target="n_checkout-api">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="610.0" y="285.0" as="offset"/>
|
||||
<mxPoint x="610.0" y="200.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
|
||||
@@ -3,90 +3,12 @@
|
||||
"version": 2,
|
||||
"source": "techviz-harness",
|
||||
"elements": [
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"x": 50,
|
||||
"y": 24,
|
||||
"width": 400,
|
||||
"height": 36,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 867999238,
|
||||
"version": 1,
|
||||
"versionNonce": 149105586,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 24,
|
||||
"fontFamily": 5,
|
||||
"text": "승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "question",
|
||||
"type": "text",
|
||||
"x": 50,
|
||||
"y": 62,
|
||||
"width": 500,
|
||||
"height": 26,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 525371355,
|
||||
"version": 1,
|
||||
"versionNonce": 153533324,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 14,
|
||||
"fontFamily": 5,
|
||||
"text": "결제 요청은 어디를 거쳐 저장되고 승인 후 어떤 이벤트를 발행하는가?",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "결제 요청은 어디를 거쳐 저장되고 승인 후 어떤 이벤트를 발행하는가?",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-authorization-approved",
|
||||
"type": "arrow",
|
||||
"x": 765.0,
|
||||
"y": 345.0,
|
||||
"width": 312.20000000000005,
|
||||
"y": 260.0,
|
||||
"width": 311.5,
|
||||
"height": 182.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -110,11 +32,11 @@
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
312.20000000000005,
|
||||
311.5,
|
||||
136.0
|
||||
],
|
||||
[
|
||||
312.20000000000005,
|
||||
311.5,
|
||||
182.0
|
||||
],
|
||||
[
|
||||
@@ -144,8 +66,8 @@
|
||||
{
|
||||
"id": "edge-label-authorization-approved",
|
||||
"type": "text",
|
||||
"x": 808.1,
|
||||
"y": 487.0,
|
||||
"x": 807.75,
|
||||
"y": 402.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -184,9 +106,9 @@
|
||||
"id": "edge-authorization-request",
|
||||
"type": "arrow",
|
||||
"x": 840.0,
|
||||
"y": 332.84,
|
||||
"width": 162.20000000000005,
|
||||
"height": 125.16000000000003,
|
||||
"y": 247.84,
|
||||
"width": 161.5,
|
||||
"height": 125.16,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
@@ -213,16 +135,16 @@
|
||||
0.0
|
||||
],
|
||||
[
|
||||
91.10000000000002,
|
||||
90.75,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
91.10000000000002,
|
||||
125.16000000000003
|
||||
90.75,
|
||||
125.16
|
||||
],
|
||||
[
|
||||
162.20000000000005,
|
||||
125.16000000000003
|
||||
161.5,
|
||||
125.16
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
@@ -243,8 +165,8 @@
|
||||
{
|
||||
"id": "edge-label-authorization-request",
|
||||
"type": "text",
|
||||
"x": 862.1,
|
||||
"y": 373.41999999999996,
|
||||
"x": 861.75,
|
||||
"y": 288.41999999999996,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -283,7 +205,7 @@
|
||||
"id": "edge-client-request",
|
||||
"type": "arrow",
|
||||
"x": 220.0,
|
||||
"y": 313.0,
|
||||
"y": 228.0,
|
||||
"width": 160.0,
|
||||
"height": 0.0,
|
||||
"angle": 0,
|
||||
@@ -343,7 +265,7 @@
|
||||
"id": "edge-label-client-request",
|
||||
"type": "text",
|
||||
"x": 255.0,
|
||||
"y": 273.0,
|
||||
"y": 188.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -382,9 +304,9 @@
|
||||
"id": "edge-create-pending",
|
||||
"type": "arrow",
|
||||
"x": 840.0,
|
||||
"y": 303.08,
|
||||
"y": 218.08,
|
||||
"width": 160.0,
|
||||
"height": 0.9200000000000159,
|
||||
"height": 0.9199999999999875,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
@@ -416,11 +338,11 @@
|
||||
],
|
||||
[
|
||||
80.0,
|
||||
0.9200000000000159
|
||||
0.9199999999999875
|
||||
],
|
||||
[
|
||||
160.0,
|
||||
0.9200000000000159
|
||||
0.9199999999999875
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
@@ -442,7 +364,7 @@
|
||||
"id": "edge-label-create-pending",
|
||||
"type": "text",
|
||||
"x": 892.0,
|
||||
"y": 291.53999999999996,
|
||||
"y": 206.54000000000002,
|
||||
"width": 104,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -481,7 +403,7 @@
|
||||
"id": "edge-mark-paid",
|
||||
"type": "arrow",
|
||||
"x": 840.0,
|
||||
"y": 313.0,
|
||||
"y": 228.0,
|
||||
"width": 160.0,
|
||||
"height": 9.0,
|
||||
"angle": 0,
|
||||
@@ -541,7 +463,7 @@
|
||||
"id": "edge-label-mark-paid",
|
||||
"type": "text",
|
||||
"x": 879.5,
|
||||
"y": 329.0,
|
||||
"y": 244.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -580,9 +502,9 @@
|
||||
"id": "edge-publish-approved",
|
||||
"type": "arrow",
|
||||
"x": 840.0,
|
||||
"y": 177.0,
|
||||
"width": 162.20000000000005,
|
||||
"height": 116.16000000000003,
|
||||
"y": 92.0,
|
||||
"width": 161.5,
|
||||
"height": 116.16,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
@@ -606,18 +528,18 @@
|
||||
"points": [
|
||||
[
|
||||
0.0,
|
||||
116.16000000000003
|
||||
116.16
|
||||
],
|
||||
[
|
||||
81.10000000000002,
|
||||
116.16000000000003
|
||||
80.75,
|
||||
116.16
|
||||
],
|
||||
[
|
||||
81.10000000000002,
|
||||
80.75,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
162.20000000000005,
|
||||
161.5,
|
||||
0.0
|
||||
]
|
||||
],
|
||||
@@ -639,8 +561,8 @@
|
||||
{
|
||||
"id": "edge-label-publish-approved",
|
||||
"type": "text",
|
||||
"x": 869.1,
|
||||
"y": 223.08,
|
||||
"x": 868.75,
|
||||
"y": 138.08,
|
||||
"width": 152,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -679,7 +601,7 @@
|
||||
"id": "edge-validated-request",
|
||||
"type": "arrow",
|
||||
"x": 530.0,
|
||||
"y": 313.0,
|
||||
"y": 228.0,
|
||||
"width": 160.0,
|
||||
"height": 0.0,
|
||||
"angle": 0,
|
||||
@@ -739,7 +661,7 @@
|
||||
"id": "edge-label-validated-request",
|
||||
"type": "text",
|
||||
"x": 565.0,
|
||||
"y": 273.0,
|
||||
"y": 188.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
@@ -778,9 +700,9 @@
|
||||
"id": "node-client",
|
||||
"type": "rectangle",
|
||||
"x": 70.0,
|
||||
"y": 281.0,
|
||||
"y": 186.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
"height": 84.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#ffffff",
|
||||
@@ -808,9 +730,9 @@
|
||||
"id": "node-label-client",
|
||||
"type": "text",
|
||||
"x": 80.0,
|
||||
"y": 291.0,
|
||||
"y": 196.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
@@ -847,7 +769,7 @@
|
||||
"id": "node-auth-gateway",
|
||||
"type": "rectangle",
|
||||
"x": 380.0,
|
||||
"y": 281.0,
|
||||
"y": 196.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
@@ -877,7 +799,7 @@
|
||||
"id": "node-label-auth-gateway",
|
||||
"type": "text",
|
||||
"x": 390.0,
|
||||
"y": 291.0,
|
||||
"y": 206.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
@@ -916,7 +838,7 @@
|
||||
"id": "node-checkout-api",
|
||||
"type": "rectangle",
|
||||
"x": 690.0,
|
||||
"y": 281.0,
|
||||
"y": 196.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
@@ -946,7 +868,7 @@
|
||||
"id": "node-label-checkout-api",
|
||||
"type": "text",
|
||||
"x": 700.0,
|
||||
"y": 291.0,
|
||||
"y": 206.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
@@ -984,8 +906,8 @@
|
||||
{
|
||||
"id": "node-event-bus",
|
||||
"type": "rectangle",
|
||||
"x": 1002.2,
|
||||
"y": 145.0,
|
||||
"x": 1001.5,
|
||||
"y": 60.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
@@ -1014,8 +936,8 @@
|
||||
{
|
||||
"id": "node-label-event-bus",
|
||||
"type": "text",
|
||||
"x": 1012.2,
|
||||
"y": 155.0,
|
||||
"x": 1011.5,
|
||||
"y": 70.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
@@ -1054,8 +976,8 @@
|
||||
"id": "node-orders-db",
|
||||
"type": "rectangle",
|
||||
"x": 1000.0,
|
||||
"y": 281.0,
|
||||
"width": 154.4,
|
||||
"y": 196.0,
|
||||
"width": 153.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -1084,8 +1006,8 @@
|
||||
"id": "node-label-orders-db",
|
||||
"type": "text",
|
||||
"x": 1010.0,
|
||||
"y": 291.0,
|
||||
"width": 134.4,
|
||||
"y": 206.0,
|
||||
"width": 133.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
@@ -1122,8 +1044,8 @@
|
||||
{
|
||||
"id": "node-payment-provider",
|
||||
"type": "rectangle",
|
||||
"x": 1002.2,
|
||||
"y": 417.0,
|
||||
"x": 1001.5,
|
||||
"y": 332.0,
|
||||
"width": 150.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
@@ -1152,8 +1074,8 @@
|
||||
{
|
||||
"id": "node-label-payment-provider",
|
||||
"type": "text",
|
||||
"x": 1012.2,
|
||||
"y": 427.0,
|
||||
"x": 1011.5,
|
||||
"y": 342.0,
|
||||
"width": 130.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"harness_version": "0.1.0",
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "payment-request",
|
||||
"spec_version": "1.0",
|
||||
"spec_sha256": "788512f48619a6873ba7e07979a224a2975e9ce2c69bdc9d019185d7df660357",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "a4a9b5b3093f0ff331321fa117d51a07079f2c1e5808c9d24e7f4756015e7eb6",
|
||||
"source_context": {
|
||||
"document": "examples/docs/payment-flow.md",
|
||||
"document_sha256": "d1449d2ad322f11e735bf5c98ee33311d03ff893ef91eb97b5422f6cc04b0e7c",
|
||||
@@ -23,5 +23,10 @@
|
||||
],
|
||||
"lint_issue_count": 0,
|
||||
"assumption_count": 0,
|
||||
"assumptions_allowed": false
|
||||
"assumptions_allowed": false,
|
||||
"composition_profile": "component-flow",
|
||||
"reference_ids": [
|
||||
"payment-event-flow"
|
||||
],
|
||||
"diagram_only": true
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 63 KiB |
@@ -1,96 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1214" height="587" viewBox="0 0 1214 587" role="img" aria-labelledby="diagram-title diagram-description">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1198" height="487" viewBox="0 0 1198 487" role="img" aria-labelledby="diagram-title diagram-description">
|
||||
<title id="diagram-title">승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다</title>
|
||||
<desc id="diagram-description">왼쪽에서 오른쪽으로 읽는다. 클라이언트가 HTTPS 결제 요청을 인증 게이트웨이에 보내고, 검증된 요청이 체크아웃 API로 전달된다. 체크아웃 API는 PostgreSQL에 PENDING 주문을 기록하고 결제 제공자 API에 승인을 요청한다. 승인 응답을 받으면 같은 주문을 PAID로 갱신하고 payment.approved 이벤트를 이벤트 버스에 발행한다.</desc>
|
||||
<metadata>{"techviz":{"spec_version":"1.0","id":"payment-request"},"source_context":{"document":"examples/docs/payment-flow.md","document_sha256":"d1449d2ad322f11e735bf5c98ee33311d03ff893ef91eb97b5422f6cc04b0e7c","anchor":{"kind":"marker","value":"payment-request","line":15}},"evidence_policy":"Each factual element cites source lines or is marked assumption."}</metadata>
|
||||
<metadata>{"techviz":{"spec_version":"1.1","id":"payment-request","profile":"component-flow"},"source_context":{"document":"examples/docs/payment-flow.md","document_sha256":"d1449d2ad322f11e735bf5c98ee33311d03ff893ef91eb97b5422f6cc04b0e7c","anchor":{"kind":"marker","value":"payment-request","line":15}},"evidence_policy":"Each factual element cites source lines or is marked assumption.","diagram_only":true}</metadata>
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" />
|
||||
</marker>
|
||||
<filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="2" flood-opacity="0.16" />
|
||||
</filter>
|
||||
<style>
|
||||
:root { color-scheme: light; }
|
||||
text { font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #17202a; }
|
||||
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
||||
.canvas { fill: #ffffff; }
|
||||
.diagram-title { font-size: 24px; font-weight: 700; }
|
||||
.diagram-question { font-size: 14px; fill: #4d5966; }
|
||||
.group-box { fill: #f7f9fb; stroke: #66788a; stroke-width: 1.5; stroke-dasharray: 7 5; }
|
||||
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
|
||||
.group-label-bg { fill: #ffffff; }
|
||||
.group-label { font-size: 13px; font-weight: 650; fill: #334455; }
|
||||
.edge { fill: none; stroke: #364b5f; stroke-width: 2; stroke-linejoin: round; marker-end: url(#arrow); }
|
||||
.edge.async, .edge.event, .edge.publish { stroke-dasharray: 7 5; }
|
||||
.edge.assumption { stroke-dasharray: 3 5; }
|
||||
.edge-label-bg { fill: #ffffff; stroke: #d5dce3; stroke-width: 1; rx: 5; }
|
||||
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
|
||||
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
|
||||
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
|
||||
.edge.style-dotted { stroke-dasharray: 2 5; }
|
||||
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.edge.emphasis-muted { stroke: #9ca3af; }
|
||||
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
|
||||
.edge-label-bg { fill: #ffffff; }
|
||||
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
|
||||
.node-shape { fill: #ffffff; stroke: #2d4357; stroke-width: 2; }
|
||||
.kind-external, .kind-actor, .kind-user { fill: #f5f7fa; stroke-dasharray: 6 4; }
|
||||
.kind-database, .kind-datastore, .kind-storage { fill: #eef6fb; }
|
||||
.kind-queue, .kind-event, .kind-topic { fill: #f6f1fb; }
|
||||
.kind-decision, .kind-gateway { fill: #fff7e8; }
|
||||
.kind-security, .kind-auth { fill: #fdf0f0; }
|
||||
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
|
||||
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
|
||||
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
|
||||
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
|
||||
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
|
||||
.node-shape.assumption { stroke-dasharray: 4 4; }
|
||||
.storage-bottom { fill: none; stroke: #2d4357; stroke-width: 2; }
|
||||
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
|
||||
.controller-led { fill: #4b5563; }
|
||||
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
|
||||
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
|
||||
.node-kind { font-size: 10px; letter-spacing: 0.07em; text-transform: uppercase; text-anchor: middle; fill: #5d6975; }
|
||||
.assumption-badge { font-size: 9px; font-weight: 700; fill: #7a4300; }
|
||||
.footer { font-size: 10px; fill: #697783; }
|
||||
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
|
||||
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
|
||||
.node-detail { font-size: 11px; fill: #374151; }
|
||||
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
|
||||
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
|
||||
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
|
||||
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
|
||||
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
|
||||
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
|
||||
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
|
||||
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
|
||||
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
|
||||
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="canvas" width="1214" height="587" />
|
||||
<text class="diagram-title" x="50" y="42">승인된 결제는 주문 상태 갱신 후 이벤트로 확산된다</text>
|
||||
<text class="diagram-question" x="50" y="67">결제 요청은 어디를 거쳐 저장되고 승인 후 어떤 이벤트를 발행하는가?</text>
|
||||
<polyline class="edge response" points="1077.2,481.0 1077.2,527.0 765.0,527.0 765.0,345.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="827.1" y="485.0" width="52.0" height="22" />
|
||||
<text class="edge-label" x="853.1" y="500.0">승인 응답</text>
|
||||
<polyline class="edge request" points="840.0,332.8 931.1,332.8 931.1,458.0 1002.2,458.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="881.1" y="371.4" width="52.0" height="22" />
|
||||
<text class="edge-label" x="907.1" y="386.4">승인 요청</text>
|
||||
<polyline class="edge request" points="220.0,313.0 300.0,313.0 300.0,313.0 380.0,313.0" data-evidence="11-11" />
|
||||
<rect class="edge-label-bg" x="253.6" y="271.0" width="92.8" height="22" />
|
||||
<text class="edge-label" x="300.0" y="286.0">HTTPS 결제 요청</text>
|
||||
<polyline class="edge data" points="840.0,303.1 920.0,303.1 920.0,304.0 1000.0,304.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="890.8" y="289.5" width="106.4" height="22" />
|
||||
<text class="edge-label" x="944.0" y="304.5">PENDING 주문 기록</text>
|
||||
<polyline class="edge data" points="840.0,313.0 930.0,313.0 930.0,322.0 1000.0,322.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="881.5" y="327.0" width="86.0" height="22" />
|
||||
<text class="edge-label" x="924.5" y="342.0">PAID 상태 갱신</text>
|
||||
<polyline class="edge publish" points="840.0,293.2 921.1,293.2 921.1,177.0 1002.2,177.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="871.5" y="221.1" width="147.2" height="22" />
|
||||
<text class="edge-label" x="945.1" y="236.1">payment.approved 발행</text>
|
||||
<polyline class="edge request" points="530.0,313.0 610.0,313.0 610.0,313.0 690.0,313.0" data-evidence="11-11" />
|
||||
<rect class="edge-label-bg" x="570.4" y="271.0" width="79.2" height="22" />
|
||||
<text class="edge-label" x="610.0" y="286.0">검증된 요청 전달</text>
|
||||
<rect class="canvas" width="1198" height="487" />
|
||||
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="1076.5,396.0 1076.5,442.0 765.0,442.0 765.0,260.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="827.0" y="400.0" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="852.8" y="415.0">승인 응답</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="840.0,247.8 930.8,247.8 930.8,373.0 1001.5,373.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="881.0" y="286.4" width="51.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="906.8" y="301.4">승인 요청</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="220.0,228.0 300.0,228.0 300.0,228.0 380.0,228.0" data-evidence="11-11" />
|
||||
<rect class="edge-label-bg" x="254.2" y="186.0" width="91.7" height="22" rx="3" />
|
||||
<text class="edge-label" x="300.0" y="201.0">HTTPS 결제 요청</text>
|
||||
<polyline class="edge kind-data style-solid emphasis-normal" points="840.0,218.1 920.0,218.1 920.0,219.0 1000.0,219.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="891.5" y="204.5" width="105.1" height="22" rx="3" />
|
||||
<text class="edge-label" x="944.0" y="219.5">PENDING 주문 기록</text>
|
||||
<polyline class="edge kind-data style-solid emphasis-normal" points="840.0,228.0 930.0,228.0 930.0,237.0 1000.0,237.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="882.0" y="242.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="924.5" y="257.0">PAID 상태 갱신</text>
|
||||
<polyline class="edge kind-publish style-dashed emphasis-primary semantic-dashed" points="840.0,208.2 920.8,208.2 920.8,92.0 1001.5,92.0" data-evidence="13-13" />
|
||||
<rect class="edge-label-bg" x="872.1" y="136.1" width="145.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="944.8" y="151.1">payment.approved 발행</text>
|
||||
<polyline class="edge kind-request style-solid emphasis-normal" points="530.0,228.0 610.0,228.0 610.0,228.0 690.0,228.0" data-evidence="11-11" />
|
||||
<rect class="edge-label-bg" x="570.9" y="186.0" width="78.3" height="22" rx="3" />
|
||||
<text class="edge-label" x="610.0" y="201.0">검증된 요청 전달</text>
|
||||
<g id="node-client">
|
||||
<rect class="node-shape kind-actor" data-evidence="7-7,11-11" x="70.0" y="281.0" width="150.0" height="64.0" rx="10" />
|
||||
<text class="node-kind" x="145.0" y="298.0">actor</text>
|
||||
<text class="node-label" x="145.0" y="320.0">클라이언트</text>
|
||||
<g class="actor-symbol emphasis-normal" data-evidence="7-7,11-11"><circle cx="145.0" cy="206.0" r="11.0" /><line x1="145.0" y1="222.0" x2="145.0" y2="241.0" /><line x1="127.0" y1="232.0" x2="163.0" y2="232.0" /><line x1="145.0" y1="241.0" x2="130.0" y2="258.0" /><line x1="145.0" y1="241.0" x2="160.0" y2="258.0" /></g>
|
||||
<text class="node-label" x="145.0" y="263.0">클라이언트</text>
|
||||
</g>
|
||||
<g id="node-auth-gateway">
|
||||
<rect class="node-shape kind-security" data-evidence="7-7,11-11" x="380.0" y="281.0" width="150.0" height="64.0" rx="10" />
|
||||
<text class="node-kind" x="455.0" y="298.0">security</text>
|
||||
<text class="node-label" x="455.0" y="320.0">인증 게이트웨이</text>
|
||||
<rect class="node-shape kind-security emphasis-normal role-service" data-evidence="7-7,11-11" x="380.0" y="196.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="455.0" y="226.0">인증 게이트웨이</text>
|
||||
</g>
|
||||
<g id="node-checkout-api">
|
||||
<rect class="node-shape kind-service" data-evidence="7-7,11-13" x="690.0" y="281.0" width="150.0" height="64.0" rx="10" />
|
||||
<text class="node-kind" x="765.0" y="298.0">service</text>
|
||||
<text class="node-label" x="765.0" y="320.0">체크아웃 API</text>
|
||||
<rect class="node-shape kind-service emphasis-primary role-service" data-evidence="7-7,11-13" x="690.0" y="196.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="765.0" y="226.0">체크아웃 API</text>
|
||||
</g>
|
||||
<g id="node-event-bus">
|
||||
<rect class="node-shape kind-queue" data-evidence="13-13" x="1002.2" y="145.0" width="150.0" height="64.0" rx="26" />
|
||||
<text class="node-kind" x="1077.2" y="162.0">queue</text>
|
||||
<text class="node-label" x="1077.2" y="184.0">이벤트 버스</text>
|
||||
<rect class="node-shape kind-queue emphasis-normal role-sink" data-evidence="13-13" x="1001.5" y="60.0" width="150.0" height="64.0" rx="22" />
|
||||
<text class="node-label" x="1076.5" y="90.0">이벤트 버스</text>
|
||||
</g>
|
||||
<g id="node-orders-db">
|
||||
<rect class="node-shape kind-database" data-evidence="13-13" x="1000.0" y="291.7" width="154.4" height="42.7" /><ellipse class="node-shape kind-database" cx="1077.2" cy="291.7" rx="77.2" ry="10.7" /><path class="storage-bottom" d="M 1000.0 334.3 A 77.2 10.7 0 0 0 1154.4 334.3" />
|
||||
<text class="node-kind" x="1077.2" y="298.0">database</text>
|
||||
<text class="node-label" x="1077.2" y="320.0">PostgreSQL 주문 저장소</text>
|
||||
<rect class="node-shape kind-database emphasis-normal role-store" data-evidence="13-13" x="1000.0" y="206.7" width="153.0" height="42.7" /><ellipse class="node-shape kind-database emphasis-normal role-store" cx="1076.5" cy="206.7" rx="76.5" ry="10.7" /><path class="storage-bottom" d="M 1000.0 249.3 A 76.5 10.7 0 0 0 1153.0 249.3" />
|
||||
<text class="node-label" x="1076.5" y="226.0">PostgreSQL 주문 저장소</text>
|
||||
</g>
|
||||
<g id="node-payment-provider">
|
||||
<rect class="node-shape kind-service" data-evidence="13-13" x="1002.2" y="417.0" width="150.0" height="64.0" rx="10" />
|
||||
<text class="node-kind" x="1077.2" y="434.0">service</text>
|
||||
<text class="node-label" x="1077.2" y="456.0">결제 제공자 API</text>
|
||||
<rect class="node-shape kind-service emphasis-normal role-service" data-evidence="13-13" x="1001.5" y="332.0" width="150.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="1076.5" y="362.0">결제 제공자 API</text>
|
||||
</g>
|
||||
<text class="footer" x="50" y="565.0">Generated from grounded VizSpec · editable sources are versioned separately</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 8.4 KiB |
Reference in New Issue
Block a user