Files
document-haness/docs/clean-architecture-backend-template/final/evidence/rendered/a05-f033-jpa-flyway-migration.svg
T
DongHyeonkaandClaude Opus 5 b2963105a8 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>
2026-09-04 22:51:59 +09:00

115 lines
17 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1734" viewBox="0 0 1200 1734" role="img">
<title>terminal evidence</title>
<desc>Terminal-style rendering generated from retained command output. Sensitive-looking values are redacted in the visual asset.</desc>
<rect x="1" y="1" width="1198" height="1732" rx="14" fill="#0d1117" stroke="#30363d"/>
<rect x="1" y="1" width="1198" height="44" rx="14" fill="#161b22"/>
<rect x="1" y="30" width="1198" height="14" fill="#161b22"/>
<circle cx="24" cy="22" r="6" fill="#ff5f57"/>
<circle cx="44" cy="22" r="6" fill="#febc2e"/>
<circle cx="64" cy="22" r="6" fill="#28c840"/>
<text x="92" y="27" fill="#8b949e" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">terminal evidence</text>
<text x="24" y="68" fill="#c9d1d9" font-size="15" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">$ T=adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/read</tspan><tspan x="24" dy="22">iness/PostgreSqlMigrationIntegrationTest.java
echo &#x27;# 이 카드의 상태와 생산자 태스크&#x27;
grep -n -A6 &#x27;&quot;jpa-flyway-migratio</tspan><tspan x="24" dy="22">n&quot;: {&#x27; config/jpa/readiness-cards.yaml
echo
echo &#x27;# 이 카드를 선행 조건으로 두는 카드 전수&#x27;
python3 - &lt;&lt;&#x27;PY&#x27;
import jso</tspan><tspan x="24" dy="22">n
cards = json.load(open(&#x27;config/jpa/readiness-cards.yaml&#x27;))[&#x27;cards&#x27;]
for name, card in cards.items():
if &#x27;jpa-flywa</tspan><tspan x="24" dy="22">y-migration&#x27; in card.get(&#x27;prerequisites&#x27;, []):
print(&#x27;# &#x27;, name.ljust(34), card[&#x27;state&#x27;])
print(&#x27;# 집계 게이</tspan><tspan x="24" dy="22">트 jpa-primary-foundation 의 선행 조건:&#x27;)
for p in cards[&#x27;jpa-primary-foundation&#x27;][&#x27;prerequisites&#x27;]:
print(&#x27;# &#x27;, </tspan><tspan x="24" dy="22">p)
PY
echo
echo &#x27;# 집계 게이트는 카드 id 를 이름으로 요구한다&#x27;
grep -n &quot;jpa-flyway-migration&#x27;&quot; gradle/jpa-evidence.grad</tspan><tspan x="24" dy="22">le
echo
echo &#x27;# 그 태스크가 고정한 적용 집합 셋&#x27;
grep -n &#x27;containsExactly(&quot;1&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;)\|containsExactly(&quot;0&quot;</tspan><tspan x="24" dy="22">, &quot;1&quot;)\|containsExactly(&quot;1&quot;)&#x27; &quot;$T&quot;
echo
echo &#x27;# 두 스트림의 실제 마이그레이션&#x27;
M=adapter/outbound/persistence-jpa/src/m</tspan><tspan x="24" dy="22">ain/resources/db/migration
echo -n &#x27;# postgresql : &#x27;
ls &quot;$M/postgresql&quot; | sed &#x27;s/__.*//&#x27; | sort -V | tr &#x27;\n&#x27; &#x27; &#x27;; echo</tspan><tspan x="24" dy="22">
echo -n &#x27;# jpa/core : &#x27;
ls &quot;$M/jpa/core&quot; | sed &#x27;s/__.*//&#x27; | sort -V | tr &#x27;\n&#x27; &#x27; &#x27;; echo
echo
echo &#x27;# 단언이 마지막</tspan><tspan x="24" dy="22">으로 갱신된 시점과 그 뒤 들어온 마이그레이션&#x27;
for f in &quot;$T&quot; &quot;$M/jpa/core/V2__&quot;* &quot;$M/postgresql/V9__&quot;* &quot;$M/postgresql/V10</tspan><tspan x="24" dy="22">__&quot;* &quot;$M/postgresql/V11__&quot;* &quot;$M/postgresql/V12__&quot;*; do
echo &quot;# $(git log -1 --format=&#x27;%ad %h&#x27; --date=short -- &quot;$f&quot;)</tspan><tspan x="24" dy="22"> $(basename &quot;$f&quot;)&quot;
done
echo
echo &#x27;# 같은 소스 세트가 이 실패 유형을 주석으로 적어 두었다&#x27;
L=$(find . -name PostgreSql</tspan><tspan x="24" dy="22">OptionalStreamLifecycle.java -not -path &#x27;*/build/*&#x27;)
sed -n &#x27;140,144p&#x27; &quot;$L&quot;</tspan></text>
<text x="24" y="398" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">cwd: /shared/codebase/clean-architecture-backend-template/src</tspan></text>
<text x="24" y="420" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">time: 2026-09-02T06:27:08+00:00 · exit 0</tspan></text>
<line x1="24" y1="434" x2="1176" y2="434" stroke="#30363d"/>
<text x="24" y="474" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 이 카드의 상태와 생산자 태스크</tspan></text>
<text x="24" y="496" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">72: &quot;jpa-flyway-migration&quot;: {</tspan></text>
<text x="24" y="518" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">73- &quot;state&quot;: &quot;selected&quot;,</tspan></text>
<text x="24" y="540" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">74- &quot;schema-stream&quot;: &quot;owned&quot;,</tspan></text>
<text x="24" y="562" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">75- &quot;prerequisites&quot;: [&quot;jpa-observability-lifecycle&quot;, &quot;jpa-security-baseline&quot;],</tspan></text>
<text x="24" y="584" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">76- &quot;readiness-task&quot;: &quot;:adapter:outbound:persistence-jpa:postgresqlMigrationIntegrationTest&quot;,</tspan></text>
<text x="24" y="606" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">77- &quot;required-evidence&quot;: [</tspan></text>
<text x="24" y="628" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">78- &quot;real-postgresql&quot;,</tspan></text>
<text x="24" y="650" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="672" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 이 카드를 선행 조건으로 두는 카드 전수</tspan></text>
<text x="24" y="694" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-aggregate-store selected</tspan></text>
<text x="24" y="716" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-query-model selected</tspan></text>
<text x="24" y="738" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-primary-foundation selected</tspan></text>
<text x="24" y="760" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-idempotency-owner-safe-v2 implemented-candidate</tspan></text>
<text x="24" y="782" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-outbox-storage-v2 implemented-candidate</tspan></text>
<text x="24" y="804" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-outbox-polling-delivery-v2 implemented-candidate</tspan></text>
<text x="24" y="826" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-inbox-same-store-v1 implemented-candidate</tspan></text>
<text x="24" y="848" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-fileserver-metadata-v1 implemented-candidate</tspan></text>
<text x="24" y="870" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-notification-platform-v4 implemented-candidate</tspan></text>
<text x="24" y="892" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-primary-replica not-implemented</tspan></text>
<text x="24" y="914" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-jdbc-efficiency-coordination not-implemented</tspan></text>
<text x="24" y="936" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 집계 게이트 jpa-primary-foundation 의 선행 조건:</tspan></text>
<text x="24" y="958" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-observability-lifecycle</tspan></text>
<text x="24" y="980" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-security-baseline</tspan></text>
<text x="24" y="1002" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-flyway-migration</tspan></text>
<text x="24" y="1024" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-transaction-runtime</tspan></text>
<text x="24" y="1046" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-aggregate-store</tspan></text>
<text x="24" y="1068" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-query-model</tspan></text>
<text x="24" y="1090" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1112" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 집계 게이트는 카드 id 를 이름으로 요구한다</tspan></text>
<text x="24" y="1134" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">891: &#x27;jpa-flyway-migration&#x27;,</tspan></text>
<text x="24" y="1156" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1178" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 태스크가 고정한 적용 집합 셋</tspan></text>
<text x="24" y="1200" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">47: .containsExactly(&quot;1&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;);</tspan></text>
<text x="24" y="1222" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">62: assertThat(appliedVersions(postgres, &quot;flyway_jpa_core_history&quot;)).containsExactly(&quot;0&quot;, &quot;1&quot;);</tspan></text>
<text x="24" y="1244" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">89: assertThat(appliedVersions(fresh, &quot;flyway_jpa_core_history&quot;)).containsExactly(&quot;1&quot;);</tspan></text>
<text x="24" y="1266" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">123: assertThat(appliedVersions(interrupted, &quot;flyway_readiness_interrupted&quot;)).containsExactly(&quot;1&quot;);</tspan></text>
<text x="24" y="1288" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1310" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 두 스트림의 실제 마이그레이션</tspan></text>
<text x="24" y="1332" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># postgresql : V1 V3 V4 V5 V6 V9 V10 V11 V12 </tspan></text>
<text x="24" y="1354" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa/core : V1 V2 </tspan></text>
<text x="24" y="1376" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1398" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 단언이 마지막으로 갱신된 시점과 그 뒤 들어온 마이그레이션</tspan></text>
<text x="24" y="1420" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-07-31 7eb6af5d PostgreSqlMigrationIntegrationTest.java</tspan></text>
<text x="24" y="1442" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-08-15 2f5d2fc2 V2__widen_capability_schema_stream.sql</tspan></text>
<text x="24" y="1464" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-08-15 2f5d2fc2 V9__widen_capability_schema_stream.sql</tspan></text>
<text x="24" y="1486" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-08-18 e98b56eb V10__idempotency_request_hash_varchar.sql</tspan></text>
<text x="24" y="1508" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-08-28 a24ece9c V11__durable_operation.sql</tspan></text>
<text x="24" y="1530" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 2026-08-28 a24ece9c V12__live_event_log.sql</tspan></text>
<text x="24" y="1552" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1574" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 같은 소스 세트가 이 실패 유형을 주석으로 적어 두었다</tspan></text>
<text x="24" y="1596" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> // This list is the stream&#x27;s contract, not a note about its length: the lifecycle below</tspan></text>
<text x="24" y="1618" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> // disables, re-enables and interrupts the stream and asserts the applied set is unchanged</tspan></text>
<text x="24" y="1640" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> // each time. So a migration added to the stream belongs here, and the version that landed</tspan></text>
<text x="24" y="1662" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> // without being added is why the lane failed the first time anybody ran it.</tspan></text>
<text x="24" y="1684" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> List.of(&quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;9&quot;, &quot;10&quot;),</tspan></text>
</svg>