feat: 가상화 문서들 추가

This commit is contained in:
DongHyeonka
2026-09-10 08:54:05 +09:00
parent e9f6a93327
commit 43e1aadef0
695 changed files with 153404 additions and 12754 deletions
+149 -42
View File
@@ -13,9 +13,9 @@
},
"verified": "네 패턴이 각각 다른 브랜치에 있어 단일 커밋으로 표현되지 않는다. 각 tip 에서 문서가 인용한 것을 찾아 대조했다 — pattern1 의 frontend/src/app.js 에 InMemoryWebStorage 와 redirect_uri http://localhost:8088/callback.html, pattern2 의 /token/access, pattern3 의 BffController /bff/token-boundary, pattern4 의 EdgeIdentityController /edge/me. 공통 realm(keycloak/import/keycloak-patterns-realm.json)의 client 넷과 mock-google-realm.json 도 확인했다. 저장소 HEAD 는 keycloak-session-store 작업이라 이 문서의 상태가 아니다 (2026-09-07 확인)"
},
"ssotSha256": "0625bc875ab31ca6f331e6f64bd93f26397d54f3ac6e0162f4128a53a1d97e2d",
"ssotSha256": "5a5269ed55097d21a643ffbba8853df768ae69ebed904e4d1570f2f27e3485d5",
"sourceRevision": "keycloak-patterns-lab@2026-08",
"generatedAt": "2026-09-07",
"generatedAt": "2026-09-08",
"candidateScope": {
"document": "final/document.md",
"sections": [
@@ -58,37 +58,37 @@
}
},
"assetLedger": {
"note": "final/assets/ 의 그림 13장 가운데 글감에 배정한 것과, 배정하지 않은 것의 이유를 적는다. verify-project-layout.py 의 「기록이 쓰지 않는 SSOT 그림」이 세는 숫자가 여기서 설명된다",
"note": "final/assets/ 의 그림 10장이 모두 글감에 배정돼 있다. Case 는 구조 그림과 흐름 그림을 한 장씩 갖고, Concept 은 그 기록이 설명하는 동작 하나를 갖는다",
"assigned": [
"ap1-direct-architecture",
"ap1-browser-bearer-flow",
"ap2-mediator-architecture",
"ap2-mediator-handoff-flow",
"ap3-bff-architecture",
"ap3-bff-session-flow",
"ap3-csrf-boundary",
"ap4-edge-forward-auth-flow"
"ap4-edge-trust-architecture",
"ap4-edge-forward-auth-flow",
"login-api-phase-split"
],
"unassigned": [
"unassigned": [],
"removed": [
{
"asset": [
"ap1-direct-architecture",
"ap2-mediator-architecture",
"ap3-bff-architecture",
"ap4-edge-trust-architecture"
"ap1-credential-custody",
"ap2-split-custody",
"ap3-bff-custody",
"ap4-edge-trust"
],
"reason": "같은 구조를 그린 그림이 assets/tech-log-studio/ 에 따로 있고 기록이 그것을 쓴다. 한 기록에 같은 것을 두 번 그리지 않는다"
"reason": "같은 절의 구조를 다시 그린 것이라 지웠다. SSOT 가 이미 가진 ap*-architecture 4장이 더 자세하고 document.md 가 제자리에서 싣는다. 그쪽의 렌더 결함을 고쳐서 쓴다"
},
{
"asset": [
"ap1-browser-bearer-flow",
"ap2-mediator-handoff-flow"
],
"reason": "마지막 단계인 /api/me 응답 4필드(subject·username·issuer·audience)를 두 기록의 본문이 말하지 않는다. 근거는 final/document.md L474 에 있으므로 본문을 먼저 보강해야 이을 수 있다 — 그림만 넣으면 설명 없는 주장이 남는다"
},
{
"asset": [
"four-pattern-request-boundaries",
"credential-custody-map",
"credential-contract-migration",
"login-api-phase-split"
"four-pattern-request-boundaries"
],
"reason": "네 패턴을 나란히 비교하는 그림이라 붙을 자리가 Reference 인데 Reference 에는 본문이 없다. 이 비교를 담을 Case 나 Concept 이 아직 없다"
"reason": "표로 되는 그림이라 지웠다 — 네 패턴을 같은 속성으로 늘어놓았을 뿐 관계선이 없다. 내용은 final/document.md 의 마크다운 표로 옮겼다"
}
]
},
@@ -106,7 +106,9 @@
"source": [
"final/document.md#검토한-선택지와-막힌-지점-ap1",
"final/document.md#선택의-이유와-지킨-경계-ap1",
"final/document.md#결정이-지켜지는지-확인하는-방-ap1"
"final/document.md#선택이-코드와-흐름에-반영되는-방-ap1-완주",
"final/document.md#결정이-지켜지는지-확인하는-방법-ap1",
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap1"
],
"code": [
"spa-public client",
@@ -120,16 +122,22 @@
"concept:bearer-jwt-validation-chain",
"reference:public-confidential-client-boundary"
],
"ssot-assets": [
"ap1-direct-architecture",
"ap1-browser-bearer-flow"
],
"kind": "case",
"publication": "게시됨",
"file": "oauth-oidc-auth-boundary/case/case-browser-credential-boundary.md",
"status": "게시 중",
"studioId": "bf675775-4f3e-4744-8014-f0efff51422a",
"assets": [
"ap1-custody-v3-6e0376d2"
"ap1-direct-architecture",
"ap1-browser-bearer-flow"
],
"assetFiles": [
"ap1-credential-custody"
"ap1-direct-architecture",
"ap1-browser-bearer-flow"
],
"evidenceFiles": []
},
@@ -140,7 +148,9 @@
"source": [
"final/document.md#검토한-선택지와-막힌-지점-ap2",
"final/document.md#선택의-이유와-지킨-경계-ap2",
"final/document.md#결정이-지켜지는지-확인하는-방-ap2"
"final/document.md#선택이-코드와-흐름에-반영되는-방-ap2-완주",
"final/document.md#결정이-지켜지는지-확인하는-방법-ap2",
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap2"
],
"code": [
"Spring oauth2Login mediator",
@@ -155,16 +165,22 @@
"reference:oauth-token-application-session-boundary",
"question:refresh-rotation-replica-contention"
],
"ssot-assets": [
"ap2-mediator-architecture",
"ap2-mediator-handoff-flow"
],
"kind": "case",
"publication": "게시됨",
"file": "oauth-oidc-auth-boundary/case/case-ap2-split-custody.md",
"status": "게시 중",
"studioId": "488ce49b-afa4-42a5-a2ce-de2e0653cd82",
"assets": [
"ap2-split-custody-779cb791"
"ap2-mediator-architecture",
"ap2-mediator-handoff-flow"
],
"assetFiles": [
"ap2-split-custody"
"ap2-mediator-architecture",
"ap2-mediator-handoff-flow"
],
"evidenceFiles": []
},
@@ -175,7 +191,9 @@
"source": [
"final/document.md#검토한-선택지와-막힌-지점-ap3",
"final/document.md#선택의-이유와-지킨-경계-ap3",
"final/document.md#결정이-지켜지는지-확인하는-방-ap3"
"final/document.md#선택이-코드와-흐름에-반영되는-방-ap3-완주",
"final/document.md#결정이-지켜지는지-확인하는-방법-ap3",
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap3"
],
"code": [
"bff-confidential client",
@@ -192,7 +210,9 @@
"question:bff-session-authorized-client-store"
],
"ssot-assets": [
"ap3-bff-session-flow"
"ap3-bff-architecture",
"ap3-bff-session-flow",
"ap3-csrf-boundary"
],
"kind": "case",
"publication": "게시됨",
@@ -200,13 +220,13 @@
"status": "게시 중",
"studioId": "d85bd6af-7599-4ef7-9407-6609927d5b5c",
"assets": [
"ap3-bff-custody-82fa18bd",
"ap3-csrf-split-501dd1f7",
"ap3-bff-architecture",
"ap3-csrf-boundary",
"ap3-bff-session-flow"
],
"assetFiles": [
"ap3-bff-custody",
"ap3-csrf-split",
"ap3-bff-architecture",
"ap3-csrf-boundary",
"ap3-bff-session-flow"
],
"evidenceFiles": []
@@ -218,7 +238,9 @@
"source": [
"final/document.md#검토한-선택지와-막힌-지점-ap4",
"final/document.md#선택의-이유와-지킨-경계-ap4",
"final/document.md#결정이-지켜지는지-확인하는-방-ap4"
"final/document.md#선택이-코드와-흐름에-반영되는-방-ap4-완주",
"final/document.md#결정이-지켜지는지-확인하는-방법-ap4",
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap4"
],
"code": [
"oauth2-proxy 7.15.2",
@@ -233,16 +255,22 @@
"reference:forward-auth-identity-header-trust",
"question:edge-authorization-scope"
],
"ssot-assets": [
"ap4-edge-trust-architecture",
"ap4-edge-forward-auth-flow"
],
"kind": "case",
"publication": "게시됨",
"file": "oauth-oidc-auth-boundary/case/case-ap4-identity-header-trust.md",
"status": "게시 중",
"studioId": "a0e1cc05-92b3-4dac-bce1-513ab8cd862b",
"assets": [
"ap4-edge-trust-1cff2399"
"ap4-edge-trust-architecture",
"ap4-edge-forward-auth-flow"
],
"assetFiles": [
"ap4-edge-trust"
"ap4-edge-trust-architecture",
"ap4-edge-forward-auth-flow"
],
"evidenceFiles": []
}
@@ -262,12 +290,19 @@
"reference:authorization-code-endpoint-credential-movement"
],
"kind": "concept",
"ssot-assets": [
"login-api-phase-split"
],
"publication": "게시됨",
"file": "oauth-oidc-auth-boundary/concept/concept-authorization-code-and-pkce.md",
"status": "게시 전",
"studioId": "75c6c657-3e03-47a0-a9d0-5637fce9dd3f",
"assets": [],
"assetFiles": [],
"assets": [
"login-api-phase-split"
],
"assetFiles": [
"login-api-phase-split"
],
"evidenceFiles": []
},
{
@@ -584,10 +619,10 @@
"reference:oauth-oidc-pattern-selection-criteria"
],
"kind": "reference",
"publication": "초안",
"publication": "게시됨",
"file": "oauth-oidc-auth-boundary/reference/reference-runtime-verification-order.md",
"status": "게시 전",
"studioId": "",
"studioId": "036563a1-3a43-4931-a017-0e693b591e89",
"assets": [],
"assetFiles": [],
"evidenceFiles": []
@@ -1074,7 +1109,7 @@
"id": "SSOT-learning-environment-scope",
"kindCandidate": "CONCEPT",
"sourceRefs": [
"final/document.md#문제를-어렵게-만든-제약-학습-환경"
"final/document.md#문제를-어렵게-만든-제약-현재-구현은-운영-참조-아키텍처가-아니라"
],
"summary": "현재 구현은 운영 참조 아키텍처가 아니라 관찰 가능한 학습 환경이다",
"disposition": "KEEP_IN_SSOT",
@@ -1110,7 +1145,7 @@
"id": "SSOT-four-patterns-not-a-ladder",
"kindCandidate": "REFERENCE",
"sourceRefs": [
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-사다리가-아니라"
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-네-패턴은-사다리가-아니라"
],
"summary": "네 패턴은 사다리가 아니라 서로 다른 운영 계약이다",
"disposition": "MERGE_INTO",
@@ -1129,6 +1164,78 @@
"dispositionReview": "CONFIRMED",
"target": "reference:oauth-oidc-pattern-selection-criteria",
"reason": "그 Reference 의 규칙 5 「자격 증명의 위치가 바뀌면 저장·전달·검증 주체도 바뀐다」가 같은 내용이다"
},
{
"id": "SSOT-browser-absence-scope",
"kindCandidate": "REFERENCE",
"sourceRefs": [
"final/document.md#문제를-어렵게-만든-제약-“브라우저에-없다”도-무엇이-없는지"
],
"summary": "「브라우저에 없다」를 애플리케이션 OAuth token 으로만 한정한 용어 규정과 패턴별 보관 표",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "reference:oauth-token-application-session-boundary",
"reason": "그 Reference 의 규칙 4 「브라우저에 없는 것을 범위까지 적는다」와 규칙 5 「영구 저장과 메모리 보관을 구분한다」가 이 절의 용어 규정과 표를 이미 담는다. concept:browser-credential-storage 도 같은 절을 근거로 쓴다 — 절 하나가 두 기록의 재료이지 세 번째 기록이 아니다"
},
{
"id": "SSOT-ap1-walkthrough",
"kindCandidate": "CASE",
"sourceRefs": [
"final/document.md#선택이-코드와-흐름에-반영되는-방식-ap1-완주"
],
"summary": "AP1 요청 완주 — callback code 가 브라우저 Bearer 요청이 되기까지의 입력·변환·출력·다음 홉",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "case:spa-browser-credential-boundary",
"reason": "그 Case 의 본문이 이 절을 재료로 쓴다. ap1-browser-bearer-flow 그림의 techviz context 도 이 절에서 잘라 왔다(.techviz/ap1-browser-bearer-flow/context.json 의 current_section). 완주 절을 따로 떼면 같은 패턴을 두 편이 설명한다"
},
{
"id": "SSOT-ap2-walkthrough",
"kindCandidate": "CASE",
"sourceRefs": [
"final/document.md#선택이-코드와-흐름에-반영되는-방식-ap2-완주"
],
"summary": "AP2 요청 완주 — server 의 authorized client 가 browser Bearer 가 되기까지",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "case:split-custody-access-token",
"reason": "그 Case 본문의 코드블록 8 개가 이 절에서 나왔고 ap2-mediator-handoff-flow 그림의 techviz context 도 이 절이다"
},
{
"id": "SSOT-ap3-walkthrough",
"kindCandidate": "CASE",
"sourceRefs": [
"final/document.md#선택이-코드와-흐름에-반영되는-방식-ap3-완주"
],
"summary": "AP3 요청 완주 — session cookie 가 BFF 의 downstream Bearer 가 되기까지",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "case:bff-session-csrf-responsibility",
"reason": "그 Case 본문의 코드블록 10 개가 이 절에서 나왔고 ap3-bff-session-flow 와 ap3-csrf-boundary 두 그림의 techviz context 도 이 절이다"
},
{
"id": "SSOT-ap4-walkthrough",
"kindCandidate": "CASE",
"sourceRefs": [
"final/document.md#선택이-코드와-흐름에-반영되는-방식-ap4-완주"
],
"summary": "AP4 요청 완주 — proxy session 이 trusted identity JSON 이 되기까지",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "case:identity-header-trust",
"reason": "그 Case 본문의 코드블록 8 개와 경로별 상태코드 표, header 를 늘릴 때 정할 계약 6 개가 이 절에서만 나온다. ap4-edge-forward-auth-flow 그림의 techviz context 도 이 절이다 — 그래서 이 절을 그 Case 의 source 에 넣었다"
},
{
"id": "SSOT-ap1-adopt-or-leave-criteria",
"kindCandidate": "REFERENCE",
"sourceRefs": [
"final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap1"
],
"summary": "AP1 을 다시 고를 조건과 memory-only 로는 채우지 못하는 정책, 유지할 때의 가드레일",
"disposition": "MERGE_INTO",
"dispositionReview": "CONFIRMED",
"target": "reference:oauth-oidc-pattern-selection-criteria",
"reason": "선택 조건과 「정책상 브라우저에 토큰을 둘 수 없으면 memory-only 로도 안 된다」는 그 Reference 의 규칙 2·3 이 이미 담는다. 가드레일(PKCE S256, implicit·direct grant 끄기, 300초 수명, rotation, issuer·audience 검증, CSP)은 case:spa-browser-credential-boundary 의 검증 환경과 결론에 들어 있다. AP2·AP3·AP4 의 같은 절도 독립 기록이 아니라 각 Reference·Question 의 근거로만 쓰였다"
}
],
"unlisted": [],
@@ -1139,6 +1246,6 @@
"written": 24,
"unwritten": 0,
"unlisted": 0,
"candidates": 29
"candidates": 35
}
}