Files
document-haness/docs/clean-architecture-backend-template/final/evidence/rendered/a05-f013-specificationpolicy-specification-unrestricted-probe.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

182 lines
22 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="2394" viewBox="0 0 1200 2394" 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="2392" 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">$ mkdir -p /tmp/probe
echo &#x27;# 락파일이 고정한 좌표에서 클래스패스를 만든다. Gradle 실행 없이 재현된다.&#x27;
cat &gt; /tmp/prob</tspan><tspan x="24" dy="22">e/cp.sh &lt;&lt;&#x27;CPSH&#x27;
# 락파일이 고정한 좌표에서 jar 경로를 만든다. Gradle 실행 없이 재현된다.
CACHE=$(ls -d &quot;$HOME&quot;/.gradle/</tspan><tspan x="24" dy="22">caches/modules-2/files-2.1 2&gt;/dev/null || echo /root/.gradle/caches/modules-2/files-2.1)
jars=&quot;&quot;
for coord in \
org.sp</tspan><tspan x="24" dy="22">ringframework.data:spring-data-jpa \
org.springframework.data:spring-data-commons \
com.querydsl:querydsl-core \
c</tspan><tspan x="24" dy="22">om.querydsl:querydsl-jpa \
org.springframework:spring-core \
org.springframework:spring-tx \
jakarta.persistence:j</tspan><tspan x="24" dy="22">akarta.persistence-api \
org.slf4j:slf4j-api ; do
group=${coord%%:*}; name=${coord##*:}
ver=$(grep -m1 &quot;^$group:$n</tspan><tspan x="24" dy="22">ame:&quot; adapter/outbound/persistence-jpa/gradle.lockfile | cut -d: -f3 | cut -d= -f1)
jar=$(find &quot;$CACHE/$group/$name/$v</tspan><tspan x="24" dy="22">er&quot; -name &quot;$name-$ver*.jar&quot; ! -name &#x27;*sources*&#x27; ! -name &#x27;*javadoc*&#x27; 2&gt;/dev/null | head -1)
echo &quot;$name $ver -&gt; ${jar:-</tspan><tspan x="24" dy="22">MISSING}&quot; &gt;&amp;2
jars=&quot;$jars:$jar&quot;
done
echo &quot;adapter/outbound/persistence-jpa/build/classes/java/main$jars&quot;
CPSH
CP=$(ba</tspan><tspan x="24" dy="22">sh /tmp/probe/cp.sh 2&gt;/tmp/probe/cp.log)
sed &#x27;s|/root/.gradle/caches/modules-2/files-2.1/|&lt;cache&gt;/|; s|/[0-9a-f]\{40\}/|</tspan><tspan x="24" dy="22">/|&#x27; /tmp/probe/cp.log
echo -n &#x27;# app-bootstrap 의 락파일에 querydsl 이 있는가: &#x27;
grep -c querydsl app-bootstrap/gradle</tspan><tspan x="24" dy="22">.lockfile || true
echo
echo &#x27;# 제한 없음 명세 팩토리가 어느 람다에 링크되는가&#x27;
javap -p -v -cp &quot;$CP&quot; org.springframewor</tspan><tspan x="24" dy="22">k.data.jpa.domain.Specification 2&gt;/dev/null \
| awk &#x27;/^BootstrapMethods:/,0&#x27; | sed -n &#x27;1,6p&#x27; | cut -c1-110
echo &#x27;# </tspan><tspan x="24" dy="22">그 람다의 본문&#x27;
javap -p -c -cp &quot;$CP&quot; org.springframework.data.jpa.domain.Specification 2&gt;/dev/null \
| awk &#x27;/Predicat</tspan><tspan x="24" dy="22">e lambda\$0\(/{c=4} c--&gt;0&#x27;
echo
echo &#x27;# 그 명세와 자바 널을 두 검사에 각각 넣는다&#x27;
cat &gt; /tmp/probe/SpecProbe.java &lt;&lt;&#x27;J</tspan><tspan x="24" dy="22">AVA&#x27;
import dev.caskeleton.adapter.outbound.persistence.springdata.SpecificationPolicy;
import org.springframework.data.</tspan><tspan x="24" dy="22">domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specific</tspan><tspan x="24" dy="22">ation;
/** 라이브러리가 공식으로 주는 제한 없음 명세를 정책에 넘긴다. */
public class SpecProbe {
public static void </tspan><tspan x="24" dy="22">main(String[] args) {
Pageable paged = PageRequest.of(0, 50);
Specification&lt;Object&gt; unrestricted = Specification</tspan><tspan x="24" dy="22">.unrestricted();
System.out.println(&quot;Specification.unrestricted() 가 널인가 : &quot; + (unrestricted == null));
Syst</tspan><tspan x="24" dy="22">em.out.println(&quot;그 명세의 toPredicate 가 돌려주는 값 : &quot; + unrestricted.toPredicate(null, null, null));
System.ou</tspan><tspan x="24" dy="22">t.println(&quot;requireBounded(토큰 없이) : &quot; + verdict(() -&gt; SpecificationPolicy.requireBounded(unrestricted, paged, null))</tspan><tspan x="24" dy="22">);
System.out.println(&quot;requirePredicate : &quot; + verdict(() -&gt; SpecificationPolicy.requirePredicate(unrestric</tspan><tspan x="24" dy="22">ted)));
System.out.println(&quot;requireBounded(널 명세) : &quot; + verdict(() -&gt; SpecificationPolicy.requireBounded(null, </tspan><tspan x="24" dy="22">paged, null)));
System.out.println(&quot;requirePredicate(널 명세) : &quot; + verdict(() -&gt; SpecificationPolicy.requirePredic</tspan><tspan x="24" dy="22">ate(null)));
}
private static String verdict(Runnable call) {
try {
call.run();
return &quot;통과&quot;;
</tspan><tspan x="24" dy="22">} catch (RuntimeException refused) {
return &quot;거절 — &quot; + refused.getMessage();
}
}
}
JAVA
javac -encoding UT</tspan><tspan x="24" dy="22">F-8 -cp &quot;$CP&quot; -d /tmp/probe /tmp/probe/SpecProbe.java \
&amp;&amp; java -Dstdout.encoding=UTF-8 -cp &quot;$CP:/tmp/probe&quot; SpecProbe</tspan><tspan x="24" dy="22">
echo
echo &#x27;# 페이지 경계 검사는 그대로 남아 있다&#x27;
S=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adap</tspan><tspan x="24" dy="22">ter/outbound/persistence/springdata/SpecificationPolicy.java
grep -n -A3 &#x27;pageable.isUnpaged()&#x27; &quot;$S&quot;
echo &#x27;# 반면 requ</tspan><tspan x="24" dy="22">irePredicate 는 Pageable 을 받지 않는다&#x27;
grep -n &#x27;public static void requirePredicate&#x27; &quot;$S&quot;
echo
echo &#x27;# 형제 정책에 Qu</tspan><tspan x="24" dy="22">erydsl 쪽 대응물을 넣는다&#x27;
cat &gt; /tmp/probe/SiblingProbe.java &lt;&lt;&#x27;JAVA&#x27;
import com.querydsl.core.BooleanBuilder;
import d</tspan><tspan x="24" dy="22">ev.caskeleton.adapter.outbound.persistence.querydsl.PredicatePolicy;
import dev.caskeleton.adapter.outbound.persistence.</tspan><tspan x="24" dy="22">querydsl.QueryPage;
public class SiblingProbe {
public static void main(String[] args) {
QueryPage page = QueryPa</tspan><tspan x="24" dy="22">ge.of(0, 50);
BooleanBuilder empty = new BooleanBuilder();
System.out.println(&quot;빈 BooleanBuilder 가 널인가 : &quot; +</tspan><tspan x="24" dy="22"> (empty == null));
System.out.println(&quot;hasValue : &quot; + empty.hasValue());
try {
Predicat</tspan><tspan x="24" dy="22">ePolicy.requireBounded(empty, page);
System.out.println(&quot;PredicatePolicy 판정 : 통과&quot;);
} catch (Runtim</tspan><tspan x="24" dy="22">eException refused) {
System.out.println(&quot;PredicatePolicy 판정 : 거절 — &quot; + refused.getMessage());
}
</tspan><tspan x="24" dy="22"> }
}
JAVA
javac -encoding UTF-8 -cp &quot;$CP&quot; -d /tmp/probe /tmp/probe/SiblingProbe.java \
&amp;&amp; java -Dstdout.encoding=UTF-8</tspan><tspan x="24" dy="22"> -cp &quot;$CP:/tmp/probe&quot; SiblingProbe
echo
echo &#x27;# 형제 쪽 진입점은 항상 limit 을 붙이고, 그 리프에서 Querydsl 은 compileO</tspan><tspan x="24" dy="22">nly 다&#x27;
Q=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJp</tspan><tspan x="24" dy="22">aSupport.java
sed -n &#x27;44,49p&#x27; &quot;$Q&quot;
grep -n &#x27;compileOnly.*querydsl&#x27; adapter/outbound/persistence-jpa/build.gradle
sed -n </tspan><tspan x="24" dy="22">&#x27;13,15p&#x27; &quot;$Q&quot;</tspan></text>
<text x="24" y="1014" 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="1036" 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-02T03:59:23+00:00 · exit 0</tspan></text>
<line x1="24" y1="1050" x2="1176" y2="1050" stroke="#30363d"/>
<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"># 락파일이 고정한 좌표에서 클래스패스를 만든다. Gradle 실행 없이 재현된다.</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">spring-data-jpa 4.0.7 -&gt; &lt;cache&gt;/org.springframework.data/spring-data-jpa/4.0.7/spring-data-jpa-4.0.7.jar</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">spring-data-commons 4.0.7 -&gt; &lt;cache&gt;/org.springframework.data/spring-data-commons/4.0.7/spring-data-commons-4.0.7.jar</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">querydsl-core 5.1.0 -&gt; &lt;cache&gt;/com.querydsl/querydsl-core/5.1.0/querydsl-core-5.1.0.jar</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">querydsl-jpa 5.1.0 -&gt; &lt;cache&gt;/com.querydsl/querydsl-jpa/5.1.0/querydsl-jpa-5.1.0-jakarta.jar</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">spring-core 7.0.9 -&gt; &lt;cache&gt;/org.springframework/spring-core/7.0.9/spring-core-7.0.9.jar</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">spring-tx 7.0.9 -&gt; &lt;cache&gt;/org.springframework/spring-tx/7.0.9/spring-tx-7.0.9.jar</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">jakarta.persistence-api 3.2.0 -&gt; &lt;cache&gt;/jakarta.persistence/jakarta.persistence-api/3.2.0/jakarta.persistence-api-3.2.0.jar</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">slf4j-api 2.0.18 -&gt; &lt;cache&gt;/org.slf4j/slf4j-api/2.0.18/slf4j-api-2.0.18.jar</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"># app-bootstrap 의 락파일에 querydsl 이 있는가: 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"># 제한 없음 명세 팩토리가 어느 람다에 링크되는가</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">BootstrapMethods:</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"> 0: #232 REF_invokeStatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$</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"> Method arguments:</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"> #233 (Ljakarta/persistence/criteria/Root;Ljakarta/persistence/criteria/CriteriaQuery;Ljakarta/persistenc</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"> #236 REF_invokeStatic org/springframework/data/jpa/domain/Specification.lambda$0:(Ljakarta/persistence/c</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"> #237 (Ljakarta/persistence/criteria/Root;Ljakarta/persistence/criteria/CriteriaQuery;Ljakarta/persistenc</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"># 그 람다의 본문</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"> private static jakarta.persistence.criteria.Predicate lambda$0(jakarta.persistence.criteria.Root, jakarta.persistence.criteria</tspan><tspan x="24" dy="22">.CriteriaQuery, jakarta.persistence.criteria.CriteriaBuilder);</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"> Code:</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"> 0: aconst_null</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"> 1: areturn</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"></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"># 그 명세와 자바 널을 두 검사에 각각 넣는다</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">Specification.unrestricted() 가 널인가 : false</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">그 명세의 toPredicate 가 돌려주는 값 : null</tspan></text>
<text x="24" y="1706" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requireBounded(토큰 없이) : 통과</tspan></text>
<text x="24" y="1728" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requirePredicate : 통과</tspan></text>
<text x="24" y="1750" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requireBounded(널 명세) : 거절 — a specification query requires a bounded predicate, or the explicit &#x27;allow-unbounded-scan&#x27; </tspan><tspan x="24" dy="22">token</tspan></text>
<text x="24" y="1794" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requirePredicate(널 명세) : 거절 — a specification query requires a bounded predicate</tspan></text>
<text x="24" y="1816" 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="1838" 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="1860" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">34: if (pageable.isUnpaged()) {</tspan></text>
<text x="24" y="1882" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">35- throw new IllegalArgumentException(</tspan></text>
<text x="24" y="1904" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">36- &quot;a specification query requires a bounded page; unpaged reads whatever the table holds&quot;);</tspan></text>
<text x="24" y="1926" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">37- }</tspan></text>
<text x="24" y="1948" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 반면 requirePredicate 는 Pageable 을 받지 않는다</tspan></text>
<text x="24" y="1970" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">47: public static void requirePredicate(Specification&lt;?&gt; specification) {</tspan></text>
<text x="24" y="1992" 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="2014" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 형제 정책에 Querydsl 쪽 대응물을 넣는다</tspan></text>
<text x="24" y="2036" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">빈 BooleanBuilder 가 널인가 : false</tspan></text>
<text x="24" y="2058" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">hasValue : false</tspan></text>
<text x="24" y="2080" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">PredicatePolicy 판정 : 통과</tspan></text>
<text x="24" y="2102" 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="2124" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 형제 쪽 진입점은 항상 limit 을 붙이고, 그 리프에서 Querydsl 은 compileOnly 다</tspan></text>
<text x="24" y="2146" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> JPAQuery&lt;T&gt; query = queryFactory.selectFrom(root);</tspan></text>
<text x="24" y="2168" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> if (predicate != null) {</tspan></text>
<text x="24" y="2190" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> query = query.where(predicate);</tspan></text>
<text x="24" y="2212" 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="2234" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> return query.offset(page.offset()).limit(page.size()).setHint(COMMENT_HINT, name.value());</tspan></text>
<text x="24" y="2256" 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="2278" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">69: compileOnly &#x27;com.querydsl:querydsl-jpa:5.1.0:jakarta&#x27;</tspan></text>
<text x="24" y="2300" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * &lt;p&gt;Querydsl is an Advanced opt-in and is {@code compileOnly} for this leaf, so the Stable runtime</tspan></text>
<text x="24" y="2322" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * classpath never carries it. A deployment that wants it adds the artifact; one that does not is</tspan></text>
<text x="24" y="2344" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * unaffected by the existence of this class.</tspan></text>
</svg>