From 92786cee9cca6114b99d8ead5d8b81fa5bed9d1c Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Wed, 1 Oct 2025 21:06:11 +0900 Subject: [PATCH 1/9] =?UTF-8?q?fix:=20=EB=B8=8C=EB=9D=BC=EC=9A=B0=EC=A0=80?= =?UTF-8?q?=20=ED=97=88=EC=9A=A9=20=EA=B7=9C=EC=B9=99=20=EA=B0=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/common/waf/main.tf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/terraform/common/waf/main.tf b/terraform/common/waf/main.tf index 7e68559..08b7ec1 100644 --- a/terraform/common/waf/main.tf +++ b/terraform/common/waf/main.tf @@ -85,32 +85,32 @@ resource "aws_wafv2_web_acl" "this" { statement { or_statement { statement { - size_constraint_statement { + byte_match_statement { field_to_match { single_header { name = "origin" } } - comparison_operator = "GT" - size = 0 + search_string = "eatda.net" + positional_constraint = "ENDS_WITH" text_transformation { priority = 0 - type = "NONE" + type = "LOWERCASE" } } } statement { - size_constraint_statement { + byte_match_statement { field_to_match { single_header { name = "referer" } } - comparison_operator = "GT" - size = 0 + search_string = "eatda.net" + positional_constraint = "CONTAINS" text_transformation { priority = 0 - type = "NONE" + type = "LOWERCASE" } } } From b7078f3666a116f8ebc56c859bcd0ed3a12f4a17 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Thu, 2 Oct 2025 22:18:10 +0900 Subject: [PATCH 2/9] =?UTF-8?q?docs:=20=EC=9E=91=EC=97=85=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/eatda/repository/store/StoreRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eatda/repository/store/StoreRepository.java b/src/main/java/eatda/repository/store/StoreRepository.java index f1e8782..8ffa09e 100644 --- a/src/main/java/eatda/repository/store/StoreRepository.java +++ b/src/main/java/eatda/repository/store/StoreRepository.java @@ -41,6 +41,7 @@ default List findAllByConditions(@Nullable StoreCategory category, return findAll(spec, pageable); } + // Querydsl등을 이용하여 EntityGraph와 Limit 분리 필요 @EntityGraph(attributePaths = {"cheers"}) List findAll(Specification spec, Pageable pageable); From 847c1106dfcc483eaf178d1b36e64442018dd126 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Mon, 6 Oct 2025 17:26:15 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EntityGraph에서 Batchsize 조절로 쿼리 로직 변경 --- src/main/java/eatda/domain/story/Story.java | 3 +++ src/main/java/eatda/repository/story/StoryRepository.java | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/eatda/domain/story/Story.java b/src/main/java/eatda/domain/story/Story.java index 0c88224..fec5770 100644 --- a/src/main/java/eatda/domain/story/Story.java +++ b/src/main/java/eatda/domain/story/Story.java @@ -24,6 +24,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.BatchSize; @Table(name = "story") @Entity @@ -35,6 +36,7 @@ public class Story extends AuditingEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @BatchSize(size = 10) @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false) private Member member; @@ -58,6 +60,7 @@ public class Story extends AuditingEntity { @Column(name = "description") private String description; + @BatchSize(size = 10) @OneToMany(mappedBy = "story", cascade = CascadeType.ALL, orphanRemoval = true) private List images = new ArrayList<>(); diff --git a/src/main/java/eatda/repository/story/StoryRepository.java b/src/main/java/eatda/repository/story/StoryRepository.java index 20f4387..1106785 100644 --- a/src/main/java/eatda/repository/story/StoryRepository.java +++ b/src/main/java/eatda/repository/story/StoryRepository.java @@ -3,15 +3,12 @@ import eatda.domain.story.Story; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; public interface StoryRepository extends JpaRepository { - @EntityGraph(attributePaths = "images") Page findAllByOrderByCreatedAtDesc(Pageable pageable); Page findAllByMemberIdOrderByCreatedAtDesc(Long memberId, Pageable pageable); - @EntityGraph(attributePaths = {"member", "images"}) Page findAllByStoreKakaoIdOrderByCreatedAtDesc(String storeKakaoId, Pageable pageable); } From 5e260868842d7fb11c59ef7061bca2c4dc113a44 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Mon, 6 Oct 2025 19:29:28 +0900 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=86=A0=EC=96=B4=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EntityGraph에서 Batchsize 조절로 쿼리 로직 변경 --- src/main/java/eatda/domain/store/Store.java | 6 ++++++ src/main/java/eatda/domain/story/Story.java | 3 --- .../eatda/repository/store/StoreRepository.java | 16 +++++++++------- .../java/eatda/service/store/StoreService.java | 3 ++- .../repository/store/StoreRepositoryTest.java | 11 ++++++----- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/eatda/domain/store/Store.java b/src/main/java/eatda/domain/store/Store.java index fa321ab..2b2c4b6 100644 --- a/src/main/java/eatda/domain/store/Store.java +++ b/src/main/java/eatda/domain/store/Store.java @@ -57,6 +57,12 @@ public class Store extends AuditingEntity { @Embedded private Coordinates coordinates; + /* + 현재는 가게당 평균 응원 수가 5개 이하이므로 BatchSize=10이 적절함. + IN 쿼리 한 번당 최대 10개 Store의 Cheer를 로딩하도록 설정. + 향후 응원 수가 증가하거나 Store 리스트 조회 규모가 커질 경우 + 성능 모니터링 후 BatchSize 조정 및 Fetch 전략 재검토 필요. + */ @OneToMany(mappedBy = "store") private List cheers = new ArrayList<>(); diff --git a/src/main/java/eatda/domain/story/Story.java b/src/main/java/eatda/domain/story/Story.java index fec5770..0c88224 100644 --- a/src/main/java/eatda/domain/story/Story.java +++ b/src/main/java/eatda/domain/story/Story.java @@ -24,7 +24,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.BatchSize; @Table(name = "story") @Entity @@ -36,7 +35,6 @@ public class Story extends AuditingEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @BatchSize(size = 10) @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false) private Member member; @@ -60,7 +58,6 @@ public class Story extends AuditingEntity { @Column(name = "description") private String description; - @BatchSize(size = 10) @OneToMany(mappedBy = "story", cascade = CascadeType.ALL, orphanRemoval = true) private List images = new ArrayList<>(); diff --git a/src/main/java/eatda/repository/store/StoreRepository.java b/src/main/java/eatda/repository/store/StoreRepository.java index 8ffa09e..1fd34e6 100644 --- a/src/main/java/eatda/repository/store/StoreRepository.java +++ b/src/main/java/eatda/repository/store/StoreRepository.java @@ -8,9 +8,9 @@ import eatda.exception.BusinessException; import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.lang.Nullable; @@ -33,7 +33,7 @@ default Store getById(Long id) { """) List findAllByCheeredMemberId(long memberId); - default List findAllByConditions(@Nullable StoreCategory category, + default Page findAllByConditions(@Nullable StoreCategory category, List cheerTagNames, List districts, Pageable pageable) { @@ -41,9 +41,7 @@ default List findAllByConditions(@Nullable StoreCategory category, return findAll(spec, pageable); } - // Querydsl등을 이용하여 EntityGraph와 Limit 분리 필요 - @EntityGraph(attributePaths = {"cheers"}) - List findAll(Specification spec, Pageable pageable); + Page findAll(Specification spec, Pageable pageable); private Specification createSpecification(@Nullable StoreCategory category, List cheerTagNames, @@ -53,8 +51,12 @@ private Specification createSpecification(@Nullable StoreCategory categor spec = spec.and((root, query, cb) -> cb.equal(root.get("category"), category)); } if (!cheerTagNames.isEmpty()) { - spec = spec.and(((root, query, cb) -> - root.join("cheers").join("cheerTags").join("values").get("name").in(cheerTagNames))); + spec = spec.and(((root, query, cb) -> { + if (query != null) { + query.distinct(true); + } + return root.join("cheers").join("cheerTags").join("values").get("name").in(cheerTagNames); + })); } if (!districts.isEmpty()) { spec = spec.and((root, query, cb) -> root.get("district").in(districts)); diff --git a/src/main/java/eatda/service/store/StoreService.java b/src/main/java/eatda/service/store/StoreService.java index d860957..fafb627 100644 --- a/src/main/java/eatda/service/store/StoreService.java +++ b/src/main/java/eatda/service/store/StoreService.java @@ -19,6 +19,7 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; @@ -45,7 +46,7 @@ public StoreResponse getStore(long storeId) { // TODO : N+1 문제 해결 @Transactional(readOnly = true) public StoresResponse getStores(StoreSearchParameters parameters) { - List stores = storeRepository.findAllByConditions( + Page stores = storeRepository.findAllByConditions( parameters.getCategory(), parameters.getCheerTagNames(), parameters.getDistricts(), diff --git a/src/test/java/eatda/repository/store/StoreRepositoryTest.java b/src/test/java/eatda/repository/store/StoreRepositoryTest.java index 43cf7ac..93ab512 100644 --- a/src/test/java/eatda/repository/store/StoreRepositoryTest.java +++ b/src/test/java/eatda/repository/store/StoreRepositoryTest.java @@ -14,6 +14,7 @@ import java.util.List; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; class StoreRepositoryTest extends BaseRepositoryTest { @@ -61,7 +62,7 @@ class FindAllByConditions { Store store2 = storeGenerator.generate("1236", "서울시 강남구 역삼동 123-45", StoreCategory.WESTERN, startAt); Store store3 = storeGenerator.generate("1237", "서울시 강남구 역삼동 123-45", StoreCategory.KOREAN, startAt); - List actual = storeRepository.findAllByConditions( + Page actual = storeRepository.findAllByConditions( StoreCategory.KOREAN, List.of(), List.of(), Pageable.unpaged()); assertThat(actual).map(Store::getId) @@ -87,7 +88,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer2_2, List.of(CheerTagName.CLEAN_RESTROOM)); cheerTagGenerator.generate(cheer3_1, List.of(CheerTagName.ENERGETIC, CheerTagName.QUIET)); - List actual = storeRepository.findAllByConditions(null, + Page actual = storeRepository.findAllByConditions(null, List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM), List.of(), Pageable.unpaged()); assertThat(actual).map(Store::getId) @@ -100,7 +101,7 @@ class FindAllByConditions { Store store2 = storeGenerator.generate("1236", "서울시 강남구 역삼동 123-45", District.GANGNAM); Store store3 = storeGenerator.generate("1237", "서울시 성북구 석관동 123-45", District.SEONGBUK); - List actual = storeRepository.findAllByConditions( + Page actual = storeRepository.findAllByConditions( null, List.of(), List.of(District.GANGNAM), Pageable.unpaged()); assertThat(actual).map(Store::getId) @@ -134,7 +135,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer4_2, List.of(CheerTagName.INSTAGRAMMABLE)); cheerTagGenerator.generate(cheer5_2, List.of(CheerTagName.CLEAN_RESTROOM, CheerTagName.ENERGETIC)); - List actual = storeRepository.findAllByConditions(StoreCategory.KOREAN, + Page actual = storeRepository.findAllByConditions(StoreCategory.KOREAN, List.of(CheerTagName.CLEAN_RESTROOM), List.of(District.GANGNAM), Pageable.unpaged()); assertThat(actual).map(Store::getId) @@ -157,7 +158,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer2_1, List.of(CheerTagName.CLEAN_RESTROOM)); cheerTagGenerator.generate(cheer2_2, List.of(CheerTagName.CLEAN_RESTROOM)); - List actual = storeRepository.findAllByConditions(null, List.of(), List.of(), Pageable.unpaged()); + Page actual = storeRepository.findAllByConditions(null, List.of(), List.of(), Pageable.unpaged()); assertThat(actual).map(Store::getId) .containsExactlyInAnyOrder(store1.getId(), store2.getId(), store3.getId()); From 793197572db5944b670ba024df20390c23665883 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Mon, 6 Oct 2025 19:29:35 +0900 Subject: [PATCH 5/9] =?UTF-8?q?refactor:=20=EC=9D=91=EC=9B=90=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EntityGraph에서 Batchsize 조절로 쿼리 로직 변경 --- src/main/java/eatda/domain/cheer/Cheer.java | 6 ++++++ .../eatda/repository/cheer/CheerRepository.java | 14 +++++++------- .../java/eatda/service/cheer/CheerService.java | 15 ++++++++++----- .../repository/cheer/CheerRepositoryTest.java | 11 ++++++----- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/main/java/eatda/domain/cheer/Cheer.java b/src/main/java/eatda/domain/cheer/Cheer.java index 9cde5a3..da91e06 100644 --- a/src/main/java/eatda/domain/cheer/Cheer.java +++ b/src/main/java/eatda/domain/cheer/Cheer.java @@ -49,6 +49,12 @@ public class Cheer extends AuditingEntity { @OneToMany(mappedBy = "cheer", cascade = CascadeType.ALL, orphanRemoval = true) private Set images = new HashSet<>(); + /* + CheerTags가 Embedded이기 때문에 BatchSize를 그대로 적용하지 못함. + 성능을 위해서는 Embedded 제거 후 직접 @OneToMany로 매핑 필요함. + 현재 데이터가 많지 않음으로 현상 유지하며 모니터링. + 추후 재설계 필요 + */ @Embedded private CheerTags cheerTags; diff --git a/src/main/java/eatda/repository/cheer/CheerRepository.java b/src/main/java/eatda/repository/cheer/CheerRepository.java index f1c9a5c..7ac98dd 100644 --- a/src/main/java/eatda/repository/cheer/CheerRepository.java +++ b/src/main/java/eatda/repository/cheer/CheerRepository.java @@ -8,19 +8,18 @@ import eatda.domain.store.StoreCategory; import jakarta.persistence.criteria.JoinType; import java.util.List; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.lang.Nullable; public interface CheerRepository extends JpaRepository { - @EntityGraph(attributePaths = {"member", "cheerTags.values"}) - List findAllByStoreOrderByCreatedAtDesc(Store store, PageRequest pageRequest); + Page findAllByStoreOrderByCreatedAtDesc(Store store, PageRequest pageRequest); - default List findAllByConditions(@Nullable StoreCategory category, + default Page findAllByConditions(@Nullable StoreCategory category, List cheerTagNames, List districts, Pageable pageable) { Specification spec = createSpecification(category, cheerTagNames, districts); @@ -36,7 +35,9 @@ private Specification createSpecification(@Nullable StoreCategory categor } if (!cheerTagNames.isEmpty()) { spec = spec.and(((root, query, cb) -> { - query.distinct(true); + if (query != null) { + query.distinct(true); + } return root.join("cheerTags").join("values", JoinType.LEFT) .get("name").in(cheerTagNames); })); @@ -47,8 +48,7 @@ private Specification createSpecification(@Nullable StoreCategory categor return spec; } - @EntityGraph(attributePaths = {"store", "member", "cheerTags.values"}) - List findAll(Specification specification, Pageable pageable); + Page findAll(Specification specification, Pageable pageable); int countByMember(Member member); diff --git a/src/main/java/eatda/service/cheer/CheerService.java b/src/main/java/eatda/service/cheer/CheerService.java index 7d2ee25..ca91087 100644 --- a/src/main/java/eatda/service/cheer/CheerService.java +++ b/src/main/java/eatda/service/cheer/CheerService.java @@ -25,6 +25,7 @@ import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; @@ -115,12 +116,15 @@ private void saveCheerImages(Cheer cheer, @Transactional(readOnly = true) public CheersResponse getCheers(CheerSearchParameters parameters) { - List cheers = cheerRepository.findAllByConditions( + Page cheerPage = cheerRepository.findAllByConditions( parameters.getCategory(), parameters.getCheerTagNames(), parameters.getDistricts(), - PageRequest.of(parameters.getPage(), parameters.getSize(), Sort.by(Direction.DESC, "createdAt")) + PageRequest.of(parameters.getPage(), parameters.getSize(), + Sort.by(Direction.DESC, "createdAt")) ); + + List cheers = cheerPage.getContent(); return toCheersResponse(cheers); } @@ -140,11 +144,12 @@ private CheersResponse toCheersResponse(List cheers) { @Transactional(readOnly = true) public CheersInStoreResponse getCheersByStoreId(Long storeId, int page, int size) { Store store = storeRepository.getById(storeId); - List cheers = cheerRepository.findAllByStoreOrderByCreatedAtDesc(store, PageRequest.of(page, size)); + Page cheersPage = cheerRepository.findAllByStoreOrderByCreatedAtDesc(store, PageRequest.of(page, size)); - List cheersResponse = cheers.stream() + List cheersResponse = cheersPage.getContent().stream() .map(CheerInStoreResponse::new) - .toList(); // TODO N+1 문제 해결 + .toList(); + return new CheersInStoreResponse(cheersResponse); } } diff --git a/src/test/java/eatda/repository/cheer/CheerRepositoryTest.java b/src/test/java/eatda/repository/cheer/CheerRepositoryTest.java index 991b45e..fd30199 100644 --- a/src/test/java/eatda/repository/cheer/CheerRepositoryTest.java +++ b/src/test/java/eatda/repository/cheer/CheerRepositoryTest.java @@ -13,6 +13,7 @@ import java.util.List; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; class CheerRepositoryTest extends BaseRepositoryTest { @@ -64,7 +65,7 @@ class FindAllByConditions { Cheer cheer2_2 = cheerGenerator.generateCommon(member2, store2); Cheer cheer3_2 = cheerGenerator.generateCommon(member2, store3); - List actual = cheerRepository.findAllByConditions( + Page actual = cheerRepository.findAllByConditions( StoreCategory.KOREAN, List.of(), List.of(), Pageable.unpaged()); assertThat(actual).map(Cheer::getId) @@ -90,7 +91,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer2_2, List.of(CheerTagName.CLEAN_RESTROOM)); cheerTagGenerator.generate(cheer3_1, List.of(CheerTagName.ENERGETIC, CheerTagName.QUIET)); - List actual = cheerRepository.findAllByConditions(null, + Page actual = cheerRepository.findAllByConditions(null, List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM), List.of(), Pageable.unpaged()); assertThat(actual) @@ -110,7 +111,7 @@ class FindAllByConditions { Cheer cheer2_2 = cheerGenerator.generateCommon(member2, store2); Cheer cheer3_2 = cheerGenerator.generateCommon(member2, store3); - List actual = cheerRepository.findAllByConditions( + Page actual = cheerRepository.findAllByConditions( null, List.of(), List.of(District.GANGNAM), Pageable.unpaged()); assertThat(actual) @@ -145,7 +146,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer4_2, List.of(CheerTagName.INSTAGRAMMABLE)); cheerTagGenerator.generate(cheer5_2, List.of(CheerTagName.CLEAN_RESTROOM, CheerTagName.ENERGETIC)); - List actual = cheerRepository.findAllByConditions(StoreCategory.KOREAN, + Page actual = cheerRepository.findAllByConditions(StoreCategory.KOREAN, List.of(CheerTagName.CLEAN_RESTROOM), List.of(District.GANGNAM), Pageable.unpaged()); assertThat(actual) @@ -169,7 +170,7 @@ class FindAllByConditions { cheerTagGenerator.generate(cheer2_1, List.of(CheerTagName.CLEAN_RESTROOM)); cheerTagGenerator.generate(cheer2_2, List.of(CheerTagName.CLEAN_RESTROOM)); - List actual = cheerRepository.findAllByConditions(null, List.of(), List.of(), Pageable.unpaged()); + Page actual = cheerRepository.findAllByConditions(null, List.of(), List.of(), Pageable.unpaged()); assertThat(actual) .map(Cheer::getId) From 10e9999adf71f03c6c8324e620923be854764bed Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Tue, 7 Oct 2025 01:20:39 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20default=20batch=20fetch=20size?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 3 +++ src/main/resources/application-local.yml | 1 + src/main/resources/application-prod.yml | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 42208d9..08b32a4 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -27,6 +27,9 @@ spring: jpa: hibernate: ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 30 flyway: enabled: true diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 99fa13c..50aed8c 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -22,6 +22,7 @@ spring: max-file-size: 5MB max-request-size: 20MB + # BatchSize 미적용시를 비교하기 위해 local에는 BatchSize를 추가하지 않음 jpa: hibernate: ddl-auto: validate diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 8927fd0..dc3294c 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -27,6 +27,9 @@ spring: jpa: hibernate: ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 30 flyway: enabled: true From ab0a79df3fb24726d1cbb192784af43263d5e30e Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Tue, 7 Oct 2025 23:43:08 +0900 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20dev=20=EC=84=9C=EB=B2=84=20=EB=A1=9C?= =?UTF-8?q?=EC=BB=AC=EC=97=90=EC=84=9C=20=EC=A0=91=EC=86=8D=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/common/waf/main.tf | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/terraform/common/waf/main.tf b/terraform/common/waf/main.tf index 08b7ec1..93d138c 100644 --- a/terraform/common/waf/main.tf +++ b/terraform/common/waf/main.tf @@ -114,6 +114,66 @@ resource "aws_wafv2_web_acl" "this" { } } } + statement { + byte_match_statement { + field_to_match { + single_header { + name = "origin" + } + } + search_string = "dev.eatda.net" + positional_constraint = "ENDS_WITH" + text_transformation { + priority = 0 + type = "LOWERCASE" + } + } + } + statement { + byte_match_statement { + field_to_match { + single_header { + name = "referer" + } + } + search_string = "dev.eatda.net" + positional_constraint = "CONTAINS" + text_transformation { + priority = 0 + type = "LOWERCASE" + } + } + } + statement { + byte_match_statement { + field_to_match { + single_header { + name = "origin" + } + } + search_string = "http://localhost:3000" + positional_constraint = "EXACTLY" + text_transformation { + priority = 0 + type = "NONE" + } + } + } + statement { + byte_match_statement { + field_to_match { + single_header { + name = "referer" + } + } + search_string = "http://localhost:3000/" + positional_constraint = "STARTS_WITH" + text_transformation { + priority = 0 + type = "NONE" + } + } + } } } visibility_config { From 227dea52638859a416c98e4a24d435586e217e97 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Wed, 8 Oct 2025 14:57:41 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=EB=B9=84=EC=9A=A9=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=B4=20Bot=20Contro?= =?UTF-8?q?l=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/common/waf/main.tf | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/terraform/common/waf/main.tf b/terraform/common/waf/main.tf index 93d138c..af8906d 100644 --- a/terraform/common/waf/main.tf +++ b/terraform/common/waf/main.tf @@ -262,26 +262,6 @@ resource "aws_wafv2_web_acl" "this" { } } - # Bad Bot Protection - rule { - name = "AWS-Managed-Bot-Control-Rule-Set" - priority = 60 - override_action { - none {} - } - statement { - managed_rule_group_statement { - vendor_name = "AWS" - name = "AWSManagedRulesBotControlRuleSet" - } - } - visibility_config { - cloudwatch_metrics_enabled = true - metric_name = "aws-managed-bot-control" - sampled_requests_enabled = true - } - } - # Anonymous IP list rule { name = "AWS-Managed-Anonymous-IP-List" From e87c3f28f479939abc739948b208f5510a4453fc Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Wed, 8 Oct 2025 16:03:51 +0900 Subject: [PATCH 9/9] =?UTF-8?q?docs:=20=EC=A3=BC=EC=84=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/eatda/domain/store/Store.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eatda/domain/store/Store.java b/src/main/java/eatda/domain/store/Store.java index 2b2c4b6..98bf751 100644 --- a/src/main/java/eatda/domain/store/Store.java +++ b/src/main/java/eatda/domain/store/Store.java @@ -59,7 +59,7 @@ public class Store extends AuditingEntity { /* 현재는 가게당 평균 응원 수가 5개 이하이므로 BatchSize=10이 적절함. - IN 쿼리 한 번당 최대 10개 Store의 Cheer를 로딩하도록 설정. + 데이터 증가를 고려하여 IN 쿼리 한 번당 최대 30개 Store의 Cheer를 로딩하도록 설정. 향후 응원 수가 증가하거나 Store 리스트 조회 규모가 커질 경우 성능 모니터링 후 BatchSize 조정 및 Fetch 전략 재검토 필요. */