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>
92 lines
6.1 KiB
Plaintext
92 lines
6.1 KiB
Plaintext
# 이 패키지의 네 파일과, 자기 파일 밖에서 그 이름을 쓰는 파일 수
|
|
WebRouteContract 69줄 main 2 test 1
|
|
WebRouteInventory 104줄 main 1 test 1
|
|
RouteInventoryMismatchException 18줄 main 1 test 1
|
|
SpringMvcRouteInventoryCollector 138줄 main 0 test 0
|
|
그 파일들이 어디에 있는가 :
|
|
main · admin/route/RouteInventoryMismatchException.java
|
|
main · admin/route/SpringMvcRouteInventoryCollector.java
|
|
main · admin/route/WebRouteContract.java
|
|
main · admin/route/WebRouteInventory.java
|
|
test · admin/route/WebRouteInventoryTest.java
|
|
|
|
# 수집기가 스스로 적은 역할
|
|
/**
|
|
* Reads the routes Spring MVC actually registered.
|
|
*
|
|
* <p>From the handler mapping rather than from annotations. The mapping is what the dispatcher will
|
|
* consult, so it is the only source that reflects path prefixes, conditional registration and any
|
|
* programmatic mapping — an annotation scan describes what the code says and the mapping describes
|
|
* what the deployment serves, and the gate has to be about the second.
|
|
|
|
# 그 이름이 git 추적 파일 전체에 나오는 자리
|
|
2026-08-13-web-inbound-http-api-execution-platform-implementation-plan.md:2270 - Create: `modules/web/web-admin/src/main/java/io/backend/skeleton/web/a
|
|
2026-08-13-web-inbound-http-api-execution-platform-implementation-plan.md:2344 git add 'modules/web/web-admin/src/main/java/io/backend/skeleton/web/adm
|
|
SpringMvcRouteInventoryCollector.java:27 public final class SpringMvcRouteInventoryCollector {
|
|
SpringMvcRouteInventoryCollector.java:36 public SpringMvcRouteInventoryCollector(ApiDeprecationPolicy deprecati
|
|
|
|
# 계획 문서가 같은 자리에 적은 수집기는 둘이었다
|
|
2026-08-13-web-inbound-http-api-execution-platform-implementation-plan.md:2270 SpringMvcRouteInventoryCollector
|
|
2026-08-13-web-inbound-http-api-execution-platform-implementation-plan.md:2271 SpringWebFluxRouteInventoryCollector
|
|
그중 이 저장소 소스에 실제로 있는 것 : SpringMvcRouteInventoryCollector.java (끝)
|
|
|
|
# 목록을 만드는 자리와 예외를 던지는 자리
|
|
main 에서 WebRouteInventory 를 새로 만드는 파일 : SpringMvcRouteInventoryCollector.java (끝)
|
|
main 에서 RouteInventoryMismatchException 을 던지는 파일 : WebRouteInventory.java (끝)
|
|
requireRegisteredOperations 가 나오는 자리 :
|
|
main · WebRouteInventory.java:50
|
|
test · WebRouteInventoryTest.java:57
|
|
test · WebRouteInventoryTest.java:72
|
|
네 클래스에 스프링 애너테이션이 붙은 줄 수 : 0
|
|
|
|
# versionOf 가 찾는 모양을 선언한 main 자리 전부
|
|
OperationHttpController.java:43 public static final String BASE_PATH = "/api/v1/operations";
|
|
ReactiveOperationHttpController.java:44 public static final String BASE_PATH = "/api/v1/operations";
|
|
그 둘을 가두는 조건 :
|
|
// Gated, because the durable operation store only exists when a persistence adapter provides one.
|
|
// Without the gate this controller is component-scanned into every deployment and the context
|
|
// fails to start with an unsatisfied dependency — which is exactly what happened, and what the
|
|
// all-adapters-off startup contract caught.
|
|
@ConditionalOnProperty(
|
|
prefix = "app.web-platform.durable-operations",
|
|
name = "enabled",
|
|
havingValue = "true")
|
|
그 속성이 저장소에 나오는 자리 전부 :
|
|
OperationHttpController.java:36
|
|
ReactiveOperationHttpController.java:37
|
|
|
|
# 경로 접두를 정하는 자리 전부 (src 안의 리소스와 시험)
|
|
adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/settings/PresentationSettingsTest.java:22 api-base-path=/api
|
|
adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/settings/PresentationSettingsTest.java:44 api-base-path=api
|
|
app-bootstrap/src/main/resources/application-local.yml:164 api-base-path: /api
|
|
app-bootstrap/src/main/resources/application.yml:635 api-base-path: ${PRESENTATION_API_BASE_PATH:/v1}
|
|
app-bootstrap/src/main/resources/application.yml:688 api-base-path defaults to /v1
|
|
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/security/PublicHealthPathAgreementTest.java:19 api-base-path} defaulted to {@code /v1} and {@code
|
|
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/security/PublicHealthPathAgreementTest.java:38 api-base-path
|
|
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/security/PublicHealthPathAgreementTest.java:64 api-base-path
|
|
app-bootstrap/src/test/resources/application-test.yml:114 api-base-path:
|
|
sample-portfolio/src/main/resources/application.yml:183 api-base-path: ${PRESENTATION_API_BASE_PATH:/api}
|
|
sample-portfolio/src/test/java/dev/caskeleton/sample/portfolio/adapter/inbound/web/versioning/VersioningPrefixTest.java:34 api-base-path=/v1
|
|
sample-portfolio/src/test/resources/application-test.yml:114 api-base-path: /api
|
|
배포 레인이 고르는 프로파일 :
|
|
docker-compose.dev.yml:37 SPRING_PROFILES_ACTIVE: "dev"
|
|
docker-compose.prod-smoke.yml:18 SPRING_PROFILES_ACTIVE: "prod"
|
|
src/.env:8 SPRING_PROFILES_ACTIVE=local
|
|
|
|
# 접두 /api 에서 정규식에 걸릴 수 있는 컨트롤러와 그 조건
|
|
게이트된 web main 파일 중 /v1 경로를 선언한 것 : FileDownloadController.java FileUploadController.java Draft12UploadController.java FileLifecycleController.java TusController.java
|
|
같은 속성을 참조하는 web main 파일 / 저장소 전체 main 파일 : 9 / 29
|
|
src/.env:161:APP_FILESERVER_PLATFORM_ENABLED=false
|
|
src/.env.example:240:APP_FILESERVER_PLATFORM_ENABLED=false
|
|
application.yml:854: enabled: ${APP_FILESERVER_PLATFORM_ENABLED:false}
|
|
|
|
# 시험은 목록을 무엇으로 채우는가
|
|
123: private static WebRouteContract route(String operation, String method, String path, int version) {
|
|
124- return new WebRouteContract(
|
|
125- new WebRouteId(method + " " + path),
|
|
126- new WebOperationName(operation.length() >= 3 ? operation : "op." + operation),
|
|
127- new ApiMajorVersion(version),
|
|
128- HttpMethodSemantic.valueOf(method),
|
|
129- path,
|
|
그 시험이 RequestMappingHandlerMapping 을 쓰는가 : 0
|