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

62 lines
4.4 KiB
Plaintext

# 문서가 무엇을 막겠다고 하는가 — 두 가지다
7:/**
8: * The rules a dynamic {@link Specification} query must satisfy before it runs (design §23.2).
9: *
10: * <p>A specification with no predicate is a full table scan wearing a builder's clothing. It is
11: * usually the result of every optional filter being absent — a search screen submitted empty — and
12: * it looks harmless in code review because no single line is wrong. Requiring either a predicate or
13: * an explicit "yes, scan everything" token makes that case a decision instead of an accident.
14: *
15: * <p>A page bound is required for the same reason: an unbounded collection query hydrates whatever
16: * the table happens to hold today.
17: */
# 실제 검사
31: public static void requireBounded(
32: Specification<?> specification, Pageable pageable, String allowUnboundedToken) {
33: Objects.requireNonNull(pageable, "pageable");
34: if (pageable.isUnpaged()) {
35: throw new IllegalArgumentException(
36: "a specification query requires a bounded page; unpaged reads whatever the table holds");
37: }
38: if (specification == null && !ALLOW_UNBOUNDED_TOKEN.equals(allowUnboundedToken)) {
39: throw new IllegalArgumentException(
40: "a specification query requires a bounded predicate, or the explicit '"
41: + ALLOW_UNBOUNDED_TOKEN
42: + "' token");
43: }
44: }
45:
46: /** Fails when the specification has no predicate at all. */
47: public static void requirePredicate(Specification<?> specification) {
48: if (specification == null) {
49: throw new IllegalArgumentException("a specification query requires a bounded predicate");
50: }
51: }
# 이 타입을 언급하는 곳 (레포 전체, 언어 무관)
docs/superpowers/plans/2026-08-11-jpa-persistence-platform-implementation-plan.md:1848:- Create: `modules/jpa/jpa-spring-data/src/main/java/io/backend
docs/superpowers/plans/2026-08-11-jpa-persistence-platform-implementation-plan.md:1922:git add 'modules/jpa/jpa-querydsl/src/main/java/io/backend/skel
docs/architecture/jpa-api-surface.txt:321:dev.caskeleton.adapter.outbound.persistence.springdata.SpecificationPolicy
docs/study/postgresql-jpa-walkthrough.ko.md:874:`SpecificationPolicy`:
docs/study/postgresql-jpa-walkthrough.ko.md:3249:SpecificationPolicy
docs/study/postgresql-jpa-walkthrough.ko.md:3257:grep -rn "UpsertExecutor\|WorkClaimExecutor\|RangeQuerySupport\|SpecificationPolicy\|PgRangeJdbcType"
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:18:public final cla
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:23: private Specif
# 두 검사 메서드를 부르는 코드 (정적 임포트 포함, 레포 전체): 0
# 같은 리프의 형제 정책. 같은 토큰을 쓰고 같은 널 비교를 한다.
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:21: public static final String ALLOW_UNBOUNDED_TOKEN = "allow-unbounded-scan";
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/PredicatePolicy.java:20: public static final String ALLOW_UNBOUNDED_TOKEN = "allow-unbounded-scan";
29: public static void requireBounded(Predicate predicate, QueryPage page) {
30: Objects.requireNonNull(page, "page");
31: if (predicate == null && !page.allowsUnboundedScan()) {
32: throw new IllegalArgumentException(
33: "a collection query requires a bounded predicate, or the explicit '"
34: + ALLOW_UNBOUNDED_TOKEN
35: + "' token");
36: }
# 형제 쪽 호출처와 그것을 부르는 테스트
adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupportTest.java:17: assertThatThrownBy(() -> PredicatePolicy.requireBounded(null, QueryPage.of(0, 100)))
adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupportTest.java:25: assertThatCode(() -> PredicatePolicy.requireBounded(null, QueryPage.unboundedScan(0, 100)))
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupport.java:42: PredicatePolicy.requireBounded(predicate, page);