--- schemaVersion: 1 exampleOnly: true generationAllowed: false project: backend-clean-architecture sourceDocument: final/document.md sourceDocumentSha256: sourceRevision: generatedAt: --- # Root Tree Example > 이 파일은 **구조 예시**다. 실제 `/shared/codebase/backend-clean-architecture` 분석을 수행해 만든 결과가 아니므로 downstream 문서 생성에 사용하지 않는다. 실제 프로젝트에서는 동일한 형식으로 source anchor와 evidence를 채우고 readiness를 판정한다. PROJECT backend-clean-architecture TOPIC JPA 피드 조회 성능 jpa-feed-query-performance ├── CASE │ ├── DTO 변환 과정에서 발생한 Highlight 컬렉션 N+1 │ ├── 필드 접근 없이 발생한 EAGER ToOne N+1 │ ├── Fetch Join으로 N+1을 해결하다 만난 MultiBag과 행 폭증 │ ├── Collection Fetch Join Pagination의 In-memory Paging │ ├── Projection 이후에도 1,509행을 읽은 Row Over-fetch │ └── Visibility OR이 Keyset Index를 깨뜨린 문제 │ ├── REFERENCE │ ├── JPA N+1 정량 진단 기준 │ ├── Fetch Type과 Fetch Strategy 구분 │ ├── Fetch Join · Batch · Projection 선택 기준 │ ├── Top-N-per-group 선택 기준 │ ├── Keyset Pagination 설계 기준 │ ├── Feed Visibility Query Pattern │ └── PostgreSQL Query Plan 측정 기준 │ ├── OPEN QUESTION │ ├── Highlight 없는 FeedItem을 허용할 것인가 │ ├── Round Trip과 Row Volume을 독립 측정할 것인가 │ ├── ANALYZE 이후 Cardinality Estimate는 어떻게 달라지는가 │ ├── feed_visible을 Production CQRS로 승격할 것인가 │ └── 실제 동시 트래픽에서도 이 구조가 안정적인가 │ └── DECISION ├── Query Plan은 실제 PostgreSQL에서 측정한다 ├── Query Strategy는 FeedQueryPort 뒤에서 소유한다 ├── Collection Fetch Join과 Pagination을 같이 사용하지 않는다 ├── Entity Graph 조회에는 Batch Fetch를 사용한다 ├── 화면 조회는 Read Projection을 사용한다 ├── Feed Pagination은 Keyset을 사용한다 └── 현재 Read Model은 CQRS-lite로 유지한다 # Node Specifications ## CASE — DTO 변환 과정에서 발생한 Highlight 컬렉션 N+1 - slug: `highlight-collection-n-plus-one` - readiness: `BLOCKED` - source: - `final/document.md#컬렉션-n1-정량화` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## CASE — 필드 접근 없이 발생한 EAGER ToOne N+1 - slug: `eager-to-one-n-plus-one` - readiness: `BLOCKED` - source: - `final/document.md#user-page-연관-숨은-추가-쿼리-정량화` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## CASE — Fetch Join으로 N+1을 해결하다 만난 MultiBag과 행 폭증 - slug: `fetch-join-multibag-row-explosion` - readiness: `BLOCKED` - source: - `final/document.md#fetch-join을-적용하며-확인한-두-가지-문제` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## CASE — Collection Fetch Join Pagination의 In-memory Paging - slug: `collection-fetch-join-in-memory-pagination` - readiness: `BLOCKED` - source: - `final/document.md#컬렉션-fetch-join-페이징` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## CASE — Projection 이후에도 1,509행을 읽은 Row Over-fetch - slug: `projection-row-over-fetch` - readiness: `BLOCKED` - source: - `final/document.md#dto-프로젝션` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## CASE — Visibility OR이 Keyset Index를 깨뜨린 문제 - slug: `visibility-or-breaks-keyset-index` - readiness: `BLOCKED` - source: - `final/document.md#가시성-조건` - code: - `` - evidence: - `` - classification: `상세 분석에서 이 제목에 해당하는 구체적 발생 조건, 관측 결과, 진단 순서가 확인될 때 Case가 된다.` - missing-verification: `example only — 실제 project source/evidence 확인 필요` - relations: - `` ## REFERENCE — JPA N+1 정량 진단 기준 - slug: `jpa-n-plus-one-quantitative-diagnosis` - readiness: `BLOCKED` - source: - `final/document.md#컬렉션-n1-정량화` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — Fetch Type과 Fetch Strategy 구분 - slug: `fetch-type-vs-fetch-strategy` - readiness: `BLOCKED` - source: - `final/document.md#최초-구현과-첫-관찰` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — Fetch Join · Batch · Projection 선택 기준 - slug: `fetch-join-batch-projection-selection` - readiness: `BLOCKED` - source: - `final/document.md#배치-페치` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — Top-N-per-group 선택 기준 - slug: `top-n-per-group-selection` - readiness: `BLOCKED` - source: - `final/document.md#top-n-per-group` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — Keyset Pagination 설계 기준 - slug: `keyset-pagination-design` - readiness: `BLOCKED` - source: - `final/document.md#keyset-vs-offset` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — Feed Visibility Query Pattern - slug: `feed-visibility-query-pattern` - readiness: `BLOCKED` - source: - `final/document.md#가시성-조건` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## REFERENCE — PostgreSQL Query Plan 측정 기준 - slug: `postgresql-query-plan-measurement` - readiness: `BLOCKED` - source: - `final/document.md#측정-환경과-데이터셋` - classification: `관련 Case를 다시 서술하지 않고 다른 조회 문제에도 적용할 수 있는 판단 기준이 상세 분석에서 확인될 때 Reference가 된다.` - scope: `` - exceptions: `` - relations: - `` ## OPEN QUESTION — Highlight 없는 FeedItem을 허용할 것인가 - slug: `allow-feed-item-without-highlight` - readiness: `BLOCKED` - source: - `final/document.md#확인된-문제와-이후-검증할-가설` - known: - `` - unknown: - `` - next-verification: `` - decision-criterion: `` - relations: - `` ## OPEN QUESTION — Round Trip과 Row Volume을 독립 측정할 것인가 - slug: `measure-round-trip-and-row-volume-separately` - readiness: `BLOCKED` - source: - `final/document.md#측정-환경과-데이터셋` - known: - `` - unknown: - `` - next-verification: `` - decision-criterion: `` - relations: - `` ## OPEN QUESTION — ANALYZE 이후 Cardinality Estimate는 어떻게 달라지는가 - slug: `cardinality-estimate-after-analyze` - readiness: `BLOCKED` - source: - `final/document.md#postgresql-query-plan-측정` - known: - `` - unknown: - `` - next-verification: `` - decision-criterion: `` - relations: - `` ## OPEN QUESTION — feed_visible을 Production CQRS로 승격할 것인가 - slug: `promote-feed-visible-to-production-cqrs` - readiness: `BLOCKED` - source: - `final/document.md#cqrs-lite-읽기-모델` - known: - `` - unknown: - `` - next-verification: `` - decision-criterion: `` - relations: - `` ## OPEN QUESTION — 실제 동시 트래픽에서도 이 구조가 안정적인가 - slug: `stability-under-concurrent-traffic` - readiness: `BLOCKED` - source: - `final/document.md#다음-단계` - known: - `` - unknown: - `` - next-verification: `` - decision-criterion: `` - relations: - `` ## DECISION — Query Plan은 실제 PostgreSQL에서 측정한다 - slug: `measure-query-plan-on-postgresql` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#측정-환경과-데이터셋` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — Query Strategy는 FeedQueryPort 뒤에서 소유한다 - slug: `query-strategy-behind-feed-query-port` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#조회-전략은-포트-뒤-어댑터의-책임` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — Collection Fetch Join과 Pagination을 같이 사용하지 않는다 - slug: `no-collection-fetch-join-with-pagination` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#컬렉션-fetch-join-페이징` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — Entity Graph 조회에는 Batch Fetch를 사용한다 - slug: `batch-fetch-for-entity-graph` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#배치-페치` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — 화면 조회는 Read Projection을 사용한다 - slug: `read-projection-for-screen-query` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#dto-프로젝션` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — Feed Pagination은 Keyset을 사용한다 - slug: `keyset-for-feed-pagination` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#keyset-vs-offset` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - `` ## DECISION — 현재 Read Model은 CQRS-lite로 유지한다 - slug: `keep-cqrs-lite-read-model` - readiness: `NEEDS_DECISION` - decision-status: `NOT_DECIDED` - source: - `final/document.md#cqrs-lite-읽기-모델` - decision-evidence: - `` - grounds: - `` - classification: `상세 분석에 실제 프로젝트 선택의 근거가 확인될 때만 READY로 바뀐다. 기술적으로 합리적인 권고만으로 Decision을 만들지 않는다.` - relations: - ``