docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
43bccd08a8
commit
b2963105a8
+64
@@ -0,0 +1,64 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: a-bean-is-not-composition-evidence
|
||||
title: '@Bean이 있다는 것은 조립 증거가 아니다'
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:a-bean-is-not-composition-evidence
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# @Bean이 있다는 것은 조립 증거가 아니다
|
||||
|
||||
## 목적
|
||||
|
||||
클래스에 붙은 애너테이션이나 팩토리의 존재를 그것이 실행 컨텍스트에 있다는 증거로 읽는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 애너테이션은 후보를 만들 뿐이다
|
||||
Component 나 Repository 나 Bean 은 이 클래스가 빈이 될 수 있다는 뜻이지 빈이라는 뜻이 아니다. 스캔 범위 밖이거나 조건이 거짓이거나 소유자가 없으면 후보로 끝난다.
|
||||
|
||||
2. 이름은 아무것도 보장하지 않는다
|
||||
이름이 AutoConfiguration 으로 끝나는 클래스가 자동설정 파일에 없으면 등록되지 않는다.
|
||||
|
||||
3. 타입이 하나뿐이어도 그것이 빈이라는 뜻은 아니다
|
||||
구현이 하나뿐인 포트는 그 하나가 조립된다는 인상을 준다. 그 하나에 스테레오타입이 없고 생성하는 코드도 없으면 포트는 비어 있다.
|
||||
|
||||
4. 확인은 도달 경로로 한다
|
||||
세 경로 중 어느 것이 이 클래스를 소유하는지 묻는다. 스캔이면 범위와 제외를, 자동설정이면 imports 파일과 조건을, 명시 조립이면 그 생성 지점을 확인한다.
|
||||
|
||||
5. main 참조 0 은 강한 신호다
|
||||
프로덕션 소스에서 그 타입을 참조하는 파일이 자기 자신뿐이면, 테스트만 그것을 쓴다는 뜻이다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
능력이 활성인지 판정할 때
|
||||
|
||||
능력 리포트나 지원 매트릭스의 항목을 검증할 때
|
||||
|
||||
결함을 보고하기 전에 그 코드가 실제로 도는지 확인할 때
|
||||
|
||||
## 예외
|
||||
|
||||
명시적으로 애플리케이션이 제공하도록 설계된 포트는 플랫폼 쪽에 생산자가 없는 것이 정상이다. 그때 물을 것은 출하 애플리케이션이 그것을 제공하는가다.
|
||||
|
||||
## 예시
|
||||
|
||||
이름이 AutoConfiguration 인 세 클래스가 애너테이션도 Bean 도 imports 항목도 갖지 않은 채 능력 리포트에 Stable 로 올라 있었다.
|
||||
|
||||
스캔에서 제외된 다섯 패키지의 컴포넌트 여섯을 두 자동설정 어느 쪽도 만들지 않았다. 두 자동설정은 등록되어 실행되고 있었다.
|
||||
|
||||
JdbcOutboxRepository 는 2,276 줄이고 스프링 스테레오타입이 없으며 그것을 생성하는 main 코드가 없다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **스캔에서 뺀 다섯 패키지의 컴포넌트 여섯을 두 자동설정 어느 쪽도 소유하지 않았다**
|
||||
이 규칙이 필요한 대표 사례다.
|
||||
- **outbox가 둘이고, 출하되는 것은 messaging 플랫폼 쪽이 아니다**
|
||||
타입이 하나뿐인데도 조립되지 않는 사례다.
|
||||
- **Spring 조립의 세 경로와 각각이 결정하는 것**
|
||||
이 규칙의 확인 절차가 기대는 구조다.
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: conditionalonbean-must-be-satisfiable
|
||||
title: '@ConditionalOnBean은 조건이 만족될 수 있는지까지 확인해야 한다'
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:conditionalonbean-must-be-satisfiable
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# @ConditionalOnBean은 조건이 만족될 수 있는지까지 확인해야 한다
|
||||
|
||||
## 목적
|
||||
|
||||
조건부 빈을 선언해 두고 그 조건을 만족시킬 수 있는 경로가 있는지 확인하지 않아, 능력 전체가 조용히 없는 상태를 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 조건의 뿌리를 끝까지 따라간다
|
||||
사슬이면 뿌리 하나가 없을 때 전부 없다. 뿌리 타입의 빈을 만드는 곳이 프로덕션에 있는지 확인한다.
|
||||
|
||||
2. 테스트의 Bean 은 답이 아니다
|
||||
조건을 만족시키는 유일한 곳이 테스트 설정이면 프로덕션에서는 만족되지 않는다.
|
||||
|
||||
3. 플랫폼이 제공하지 않겠다고 선언한 경우 질문을 바꾼다
|
||||
애플리케이션이 제공해야 하는 계약이라면, 물을 것은 조건이 아니라 출하 애플리케이션이 그 계약을 이행하는가다.
|
||||
|
||||
4. 조건 불만족은 오류로 보고되지 않는다
|
||||
Spring 은 조건부 빈이 조건을 만족하지 못하는 것을 정상 동작으로 본다. 로그에도 액추에이터에도 신호가 없다.
|
||||
|
||||
5. 꺼진 것과 조립될 수 없는 것을 구별할 방법을 남긴다
|
||||
둘이 런타임에서 같아 보이면 운영자는 차이를 알 수 없다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
조건부 자동설정을 작성하거나 검토할 때
|
||||
|
||||
능력이 활성인지 판정할 때
|
||||
|
||||
조건 사슬이 두 단계 이상일 때
|
||||
|
||||
## 예외
|
||||
|
||||
의도적으로 애플리케이션이 채우도록 남긴 확장점은 조건이 프로덕션에서 거짓인 것이 정상이다. 그 경우 그 사실이 문서에 있어야 하고, 이 저장소처럼 출하 애플리케이션이 함께 있다면 그것이 채우는지 확인해야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
outbox 사슬 다섯 단계가 뿌리 두 타입의 빈에 걸려 있고, 그 두 타입을 만드는 프로덕션 코드가 없다.
|
||||
|
||||
OutboxEnvelopeFactory 를 Bean 으로 만드는 곳은 스타터의 테스트 하나뿐이다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **outbox가 둘이고, 출하되는 것은 messaging 플랫폼 쪽이 아니다**
|
||||
이 규칙을 적용해 원인이 갈린 사례다.
|
||||
- **조건부 빈의 평가 시점 — 파싱 시점과 등록 시점**
|
||||
조건이 거짓인 두 번째 이유를 다룬다.
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: count-the-frameworks-own-autoconfigurations
|
||||
title: 프레임워크가 기여하는 자동설정까지 세지 않으면 스위치가 아니다
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:count-the-frameworks-own-autoconfigurations
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 프레임워크가 기여하는 자동설정까지 세지 않으면 스위치가 아니다
|
||||
|
||||
## 목적
|
||||
|
||||
프로젝트 코드만 게이트하고 프레임워크가 기여하는 자동설정을 남겨 두어, 꺼진 능력이 여전히 자원을 잡는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 프로젝트 조건은 프레임워크 자동설정을 막지 못한다
|
||||
후보 집합에 들어온 자동설정은 자기 조건으로 판단한다. 프로젝트의 마스터 스위치는 그 판단에 참여하지 않는다.
|
||||
|
||||
2. 후보 집합을 좁히는 필터가 따로 필요하다
|
||||
AutoConfigurationImportFilter 는 어떤 프로젝트 조건보다 먼저 동작하므로 이 일을 할 수 있는 유일한 자리다.
|
||||
|
||||
3. 그 필터는 권한이 아니라 도구다
|
||||
후보를 빼는 일과 능력이 켜졌는지 판정하는 일은 다르다. 판정 권한은 루트 하나가 갖는다.
|
||||
|
||||
4. 자원 필요 여부는 능력 질문으로 묻는다
|
||||
커넥션 풀 같은 공유 자원은 한 능력의 사유물이 아니다. 그것을 필요로 하는 능력이 하나라도 활성인지를 묻는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
프레임워크가 같은 기술에 대해 자기 자동설정을 갖는 모든 능력. 데이터소스, 메시징, 캐시가 대표적이다.
|
||||
|
||||
## 예외
|
||||
|
||||
프레임워크 자동설정이 이미 프로젝트 조건과 같은 속성을 보도록 설계되어 있으면 필터가 필요 없다.
|
||||
|
||||
## 예시
|
||||
|
||||
JPA 가 꺼진 배포에서 프레임워크의 데이터소스 자동설정을 후보에서 빼는 필터가 spring.factories 에 등록되어 있다.
|
||||
|
||||
풀이 필요한지는 JPA 가 켜졌는지가 아니라 커넥션을 필요로 하는 능력이 하나라도 활성인지로 묻는다. 이 저장소는 여섯 조건의 논리합으로 판정한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **풀이 필요한지는 JPA가 켜졌나가 아니라 커넥션이 필요한 capability가 있나로 묻는다**
|
||||
이 규칙을 채택한 결정이다.
|
||||
- **꺼짐은 조건의 반복이 아니라 구조여야 한다**
|
||||
같은 목표의 짝 규칙이다.
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: off-must-be-structural
|
||||
title: '"꺼짐"은 조건의 반복이 아니라 구조여야 한다'
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:off-must-be-structural
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# "꺼짐"은 조건의 반복이 아니라 구조여야 한다
|
||||
|
||||
## 목적
|
||||
|
||||
능력을 끄는 일을 빈마다 조건을 반복하는 방식으로 처리해서, 다음 달에 추가된 빈이 조건을 잊는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 루트 하나가 조건을 소유한다
|
||||
그 루트가 자식 설정을 Import 하고 자식은 조건을 갖지 않는다. 자식에 빈이 추가되어도 자동으로 게이트된다.
|
||||
|
||||
2. 자식을 컴포넌트 스캔 밖에 둔다
|
||||
스캔이 자식 설정을 독립적으로 발견하면 마스터 스위치와 무관하게 조립된다. 스캔 제외가 루트를 유일한 입구로 만든다.
|
||||
|
||||
3. 스캔에서 뺐으면 소유자를 반드시 지정한다
|
||||
제외와 소유는 한 쌍이다. 한쪽만 하면 컴포넌트가 어디에도 없게 된다.
|
||||
|
||||
4. 스위치를 읽는 곳이 여럿이면 그중 하나만 권한을 갖는다
|
||||
같은 속성을 읽는 주체가 여럿이면 각자가 다른 것이 켜졌다고 믿는 상태가 생긴다.
|
||||
|
||||
5. 프레임워크 자신의 자동설정도 후보에서 빼야 한다
|
||||
프로젝트 조건은 그것을 막지 못한다. 후보 집합을 좁히는 필터가 따로 필요하다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
선택적 능력을 갖는 모든 모듈
|
||||
|
||||
능력이 여러 설정 클래스로 나뉘는 경우
|
||||
|
||||
## 예외
|
||||
|
||||
능력 안에서 다시 갈리는 하위 선택지는 자기 조건을 가질 수 있다. 그 조건은 마스터 스위치의 반복이 아니라 다른 질문이어야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
컴포지션 루트가 13개 패키지 접두사를 스캔에서 빼고 자동설정이 소유하게 한다. 클래스 목록이 아니라 접두사인 이유는 새 설정이 추가됐을 때 아무도 제외를 기억하지 못했다는 이유로 활성화되면 안 되기 때문이다.
|
||||
|
||||
mongo 리프에서는 세 주체가 같은 속성을 읽으며 각자 마스터처럼 행동했다. 지금은 루트 하나가 권한을 갖고, 자동설정 임포트 필터는 프레임워크 자신의 자동설정을 후보에서 빼는 일만 한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **마스터 스위치는 루트 하나가 소유하고 자식 설정은 조건을 갖지 않는다**
|
||||
이 규칙을 채택한 결정이다.
|
||||
- **넓은 스캔을 좁히자 여덟 컴포넌트에 아무것도 도달하지 않았다**
|
||||
제외만 하고 소유를 지정하지 않았을 때의 결과다.
|
||||
- **프레임워크가 기여하는 자동설정까지 세지 않으면 스위치가 아니다**
|
||||
다섯 번째 규칙을 별도로 다룬다.
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: read-the-assembling-side-first
|
||||
title: 조립 결함을 판정하려면 조립하는 쪽을 먼저 읽어야 한다
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:read-the-assembling-side-first
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 조립 결함을 판정하려면 조립하는 쪽을 먼저 읽어야 한다
|
||||
|
||||
## 목적
|
||||
|
||||
조립되는 쪽만 읽고 결함을 판정해서, 원인을 잘못 지목하고 수정 방향을 반대로 잡는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 조립하는 쪽이 원인을 갖는다
|
||||
빈이 없거나 값이 no-op 이거나 조건이 거짓인 이유는 대개 조립 지점에 있다. 조립되는 클래스만 읽으면 그 클래스가 옳게 보인다.
|
||||
|
||||
2. 타입이 요구하는 것과 조립이 넘기는 것을 비교한다
|
||||
생성자가 무언가를 필수로 만들었더라도, 그것을 우회하는 오버로드가 있고 조립이 그쪽을 부르면 요구는 지켜지지 않는다.
|
||||
|
||||
3. 같은 일을 하는 다른 구현이 이미 배선되어 있는지 본다
|
||||
조건이 만족되지 않는 이유가 그것을 대체하는 구현이 이미 있기 때문일 수 있다. 그때 문제는 조건이 아니라 정본이 정해지지 않은 중복이다.
|
||||
|
||||
4. 수정 방향은 원인 분류에서 갈린다
|
||||
조건 결함으로 읽으면 조건을 만족시키는 수정이 되고, 중복으로 읽으면 어느 쪽이 정본인지 먼저 정하는 문제가 된다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
빈이 없다, 값이 기본값이다, 능력이 동작하지 않는다 계열의 모든 판정
|
||||
|
||||
플랫폼과 애플리케이션이 한 저장소에 함께 있는 경우 특히
|
||||
|
||||
## 예외
|
||||
|
||||
조립 지점이 저장소 밖에 있는 라이브러리라면 조립하는 쪽을 읽을 수 없다. 그때는 조립 계약을 문서로 확인하고, 판정에 그 한계를 적는다.
|
||||
|
||||
## 예시
|
||||
|
||||
messaging 스타터의 outbox 조건을 조건 결함으로 읽으면 app-bootstrap 에 빈을 등록하는 수정이 된다. 조립하는 쪽을 읽으면 application-core 쪽 outbox 가 이미 배선되어 돌고 있음이 보이고, 문제는 정본이 정해지지 않은 중복이 된다.
|
||||
|
||||
발행기만 읽으면 관측이 필수 인자로 보인다. 자동설정을 읽으면 인자 수가 여섯이다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **outbox가 둘이고, 출하되는 것은 messaging 플랫폼 쪽이 아니다**
|
||||
이 규칙을 적용해 원인 분류가 바뀐 사례다.
|
||||
- **관측을 필수 생성자 인자로 만든 수정을 조립이 6인자 생성자로 되돌렸다**
|
||||
타입과 조립이 어긋난 사례다.
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: the-startup-validator-follows-the-autoconfiguration-root
|
||||
title: 시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다
|
||||
topic: assembly-ownership
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:the-startup-validator-follows-the-autoconfiguration-root
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다
|
||||
|
||||
## 목적
|
||||
|
||||
검증기 파일이 존재하고 그 테스트가 통과한다는 사실을 검증이 실행된다는 증거로 읽는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 검증기의 호출자를 센다
|
||||
프로덕션 호출자가 0 이고 테스트 호출자만 있으면 그 검증은 실행 시점에 적용되지 않는다.
|
||||
|
||||
2. 자동설정 루트가 부르는지 확인한다
|
||||
능력의 조립 지점이 검증기를 호출하지 않으면, 그 능력이 배포되기 시작해도 검증은 자동으로 시작되지 않는다.
|
||||
|
||||
3. 규칙 수와 실행 여부를 분리해서 본다
|
||||
규칙이 많고 잘 테스트되어 있다는 것은 품질의 증거이지 실행의 증거가 아니다.
|
||||
|
||||
4. 시작 실패로 드러나야 할 것이 조용하면 검증기를 의심한다
|
||||
설정 오류가 기동에서 잡히지 않고 런타임 증상으로만 나타나면, 그 검사가 배선되어 있는지 먼저 본다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
시작 검증기나 설정 검증기를 갖는 모든 능력
|
||||
|
||||
능력이 Stable 로 보고되는데 그 검증이 실제로 도는지 확인할 때
|
||||
|
||||
## 예외
|
||||
|
||||
의도적으로 라이브러리로만 제공되고 애플리케이션이 직접 호출하도록 설계된 검증기는 여기 해당하지 않는다. 그 경우 호출 방법이 문서에 있어야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
gRPC 플랫폼의 시작 검증기는 188줄에 13개 위반 규칙을 담고 있고, 호출자는 자기 테스트뿐이다. 같은 패키지의 자동설정은 106줄에 Bean 이 9개인데 검증기를 부르지 않는다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **시작 검증기 13개 규칙이 유일한 조립 지점에서 호출되지 않는다**
|
||||
이 규칙을 끌어낸 사례다.
|
||||
- **Bean 애너테이션이 있다는 것은 조립 증거가 아니다**
|
||||
같은 계열의 확인 규칙이다.
|
||||
|
||||
Reference in New Issue
Block a user