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
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
kind: PROJECT_DECISION
|
||||
slug: capability-separates-installation-from-activation
|
||||
title: capability는 스키마 적용과 사용 승인을 분리한다
|
||||
topic: owner-safe-state-machines
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: decision:capability-separates-installation-from-activation
|
||||
decisionStatus: ADOPTED
|
||||
decidedOn: 2026-08-30
|
||||
source:
|
||||
- src/adapter/outbound/persistence-jpa/src/main/resources/db/migration/postgresql/V6__capability_schema_registry_adoption.sql
|
||||
- src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/notification/NotificationSchemaActivation.java
|
||||
- analysis/05-adapter-outbound-persistence-jpa.md
|
||||
---
|
||||
|
||||
# capability는 스키마 적용과 사용 승인을 분리한다
|
||||
|
||||
## 결정문
|
||||
|
||||
능력의 스키마가 설치되었다는 사실과 그 능력을 사용해도 된다는 승인을 별개의 기록으로 둔다.
|
||||
|
||||
## 판단 이유
|
||||
|
||||
두 사실은 서로 다른 주체가 만든다. 설치는 마이그레이션이 돌면 일어나고, 승인은 운영자가 정한다.
|
||||
|
||||
하나로 묶으면 마이그레이션 배포가 곧 활성화가 된다. 그러면 단계적 활성화나 롤백 같은 운영 판단이 스키마 배포 일정에 묶인다.
|
||||
|
||||
그래서 레지스트리 테이블이 능력별로 스키마 스트림과 설치 출처와 코어 에포크를 기록한다. 설치 출처가 별도 컬럼인 것이 요점이다. 같은 스키마라도 레거시 채택으로 들어온 것과 새 스트림으로 설치된 것이 구별된다.
|
||||
|
||||
능력마다 자기 스키마 스트림을 두므로 한 능력의 스키마 변경이 다른 능력의 마이그레이션 번호를 밀지 않는다.
|
||||
|
||||
다리 마이그레이션은 자기 전제를 먼저 검사한다. 레거시 채택은 그 레거시가 실제로 있을 때만 의미가 있고, 없는데 진행하면 빈 레지스트리 위에 이후 판단이 전부 선다.
|
||||
|
||||
## 영향
|
||||
|
||||
감수하는 것
|
||||
|
||||
능력을 쓰려면 두 단계를 거쳐야 한다. 스키마만 설치하고 승인을 잊으면 그 능력은 동작하지 않는다.
|
||||
|
||||
레지스트리 자체가 관리 대상이 된다. 능력이 늘 때마다 항목이 늘고 그 정합성을 지켜야 한다.
|
||||
|
||||
마이그레이션이 전제 검사에서 실패할 수 있다. 그것이 의도이지만 배포 절차가 그 실패를 다룰 줄 알아야 한다.
|
||||
|
||||
얻는 것
|
||||
|
||||
스키마 배포와 능력 활성화가 독립적이다. 스키마를 먼저 깔아 두고 나중에 켤 수 있다.
|
||||
|
||||
설치 출처가 남아 있어 나중에 이 스키마가 어디서 왔는지 물을 수 있다.
|
||||
|
||||
## 근거
|
||||
|
||||
- **capability_schema_registry — 스키마 적용과 사용 승인의 분리**
|
||||
이 결정이 만든 구조다.
|
||||
- **지원 등급은 추론이 아니라 선언이고 증거 없이는 올라가지 않는다**
|
||||
같은 원칙이 능력 등급에 적용된 결정이다.
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
---
|
||||
kind: PROJECT_DECISION
|
||||
slug: state-machines-carry-no-stereotype
|
||||
title: 상태 기계 구현은 Spring stereotype을 갖지 않는다
|
||||
topic: owner-safe-state-machines
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: decision:state-machines-carry-no-stereotype
|
||||
decisionStatus: ADOPTED
|
||||
decidedOn: 2026-08-30
|
||||
source:
|
||||
- src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/postgresql/idempotency
|
||||
- src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/config/JpaAdapterComponentsConfig.java
|
||||
- analysis/05-adapter-outbound-persistence-jpa.md
|
||||
---
|
||||
|
||||
# 상태 기계 구현은 Spring stereotype을 갖지 않는다
|
||||
|
||||
## 결정문
|
||||
|
||||
소유자 안전 상태 기계 구현 클래스에는 컴포넌트 스캔 대상이 되는 애너테이션을 붙이지 않고, 조립은 명시적으로 한다.
|
||||
|
||||
## 판단 이유
|
||||
|
||||
이 클래스들은 어떤 데이터소스와 어떤 트랜잭션 경계에 묶이는지가 정확해야 한다. 스캔으로 들어오면 그 결정이 스캔 범위와 조건에 흩어진다.
|
||||
|
||||
같은 리프에서 그 흩어짐이 실제로 문제가 된 사례가 있다. 활성 트랜잭션 검사가 어느 데이터소스인지를 묻지 않아, 다른 데이터소스의 트랜잭션 안에서 발행된 변경이 이 저장소의 커넥션에 대해 트랜잭션 밖에서 커밋됐다.
|
||||
|
||||
명시적 조립은 그 결정을 한 자리에 모은다. 어떤 데이터소스가 어떤 저장소에 들어가는지가 코드로 보인다.
|
||||
|
||||
그리고 스캔되지 않으면 조건을 반복할 필요도 없다. 능력이 꺼진 배포에서 이 클래스들이 후보가 되는 일 자체가 없다.
|
||||
|
||||
## 영향
|
||||
|
||||
감수하는 것
|
||||
|
||||
조립 코드를 사람이 써야 한다. 새 상태 기계를 추가하면 조립 지점도 함께 고쳐야 한다.
|
||||
|
||||
조립을 잊으면 그 상태 기계가 없는 채로 배포된다. 스캔은 그 실수를 자동으로 막아 주지만 명시 조립은 그렇지 않다.
|
||||
|
||||
얻는 것
|
||||
|
||||
데이터소스와 트랜잭션 경계가 조립 지점에서 명시된다.
|
||||
|
||||
능력이 꺼진 배포에서 이 클래스들이 조건 평가 대상이 되지 않는다.
|
||||
|
||||
## 근거
|
||||
|
||||
- **활성 트랜잭션 검사가 data source를 묻지 않아 다른 커넥션에서 커밋됐다**
|
||||
조립 결정이 흩어졌을 때의 결과다.
|
||||
- **꺼짐은 조건의 반복이 아니라 구조여야 한다**
|
||||
같은 계열의 조립 원칙이다.
|
||||
- **Bean 애너테이션이 있다는 것은 조립 증거가 아니다**
|
||||
명시 조립을 확인할 때 쓰는 규칙이다.
|
||||
|
||||
Reference in New Issue
Block a user