From 126138dbc7a5895c149b34dd55987922ec3401ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Mon, 14 Oct 2024 15:54:46 +0900
Subject: [PATCH 01/13] =?UTF-8?q?[Feature]=20-=20=EC=82=AC=EC=9A=A9?=
 =?UTF-8?q?=EC=9E=90=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8?=
 =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84=20(#421)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../member/controller/MyPageController.java   |  4 +--
 .../java/kr/touroot/member/domain/Member.java |  4 ++-
 .../dto/request/ProfileUpdateRequest.java     |  5 ++-
 .../member/dto/response/ProfileResponse.java  |  1 +
 .../touroot/member/service/MemberService.java | 12 ++++++-
 .../controller/MyPageControllerTest.java      | 22 ++++++++++---
 .../kr/touroot/member/domain/MemberTest.java  |  6 ++--
 .../member/service/MemberServiceTest.java     | 31 ++++++++++++++++---
 .../service/TravelPlanFacadeServiceTest.java  |  6 +++-
 9 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/member/controller/MyPageController.java b/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
index 32ab4550b..d1ff6b989 100644
--- a/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
+++ b/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
@@ -24,7 +24,7 @@
 import org.springframework.data.web.PageableDefault;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -120,7 +120,7 @@ public ResponseEntity<Page<PlanResponse>> readTravelPlans(
                     content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
             )
     })
-    @PatchMapping("/profile")
+    @PutMapping("/profile")
     public ResponseEntity<ProfileResponse> updateProfile(
             @Valid @RequestBody ProfileUpdateRequest request,
             @NotNull MemberAuth memberAuth
diff --git a/backend/src/main/java/kr/touroot/member/domain/Member.java b/backend/src/main/java/kr/touroot/member/domain/Member.java
index 88566c6d3..bef12987c 100644
--- a/backend/src/main/java/kr/touroot/member/domain/Member.java
+++ b/backend/src/main/java/kr/touroot/member/domain/Member.java
@@ -131,8 +131,10 @@ private void validateProfileImageUrlForm(String profileImageUrl) {
         }
     }
 
-    public void changeNickname(String nickname) {
+    public void update(String nickname, String profileImageUrl) {
         validateNickname(nickname);
+        validateProfileImageUrl(profileImageUrl);
         this.nickname = nickname;
+        this.profileImageUrl = profileImageUrl;
     }
 }
diff --git a/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java b/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
index 45926ed69..fc998bb06 100644
--- a/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
+++ b/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
@@ -6,6 +6,9 @@
 public record ProfileUpdateRequest(
         @Schema(description = "사용자 닉네임", example = "아기뚜리")
         @NotBlank(message = "닉네임은 비어있을 수 없습니다.")
-        String nickname
+        String nickname,
+        @Schema(description = "사용자 프로필 사진 URL", example = "https://dev.touroot.kr/profile-image-ex.png")
+        @NotBlank(message = "프로필 사진 URL은 비어있을 수 없습니다.")
+        String profileImageUrl
 ) {
 }
diff --git a/backend/src/main/java/kr/touroot/member/dto/response/ProfileResponse.java b/backend/src/main/java/kr/touroot/member/dto/response/ProfileResponse.java
index c90b4ce2d..878c77e42 100644
--- a/backend/src/main/java/kr/touroot/member/dto/response/ProfileResponse.java
+++ b/backend/src/main/java/kr/touroot/member/dto/response/ProfileResponse.java
@@ -10,6 +10,7 @@ public static ProfileResponse from(Member member) {
         return ProfileResponse.builder()
                 .profileImageUrl(member.getProfileImageUrl())
                 .nickname(member.getNickname())
+                .profileImageUrl(member.getProfileImageUrl())
                 .build();
     }
 }
diff --git a/backend/src/main/java/kr/touroot/member/service/MemberService.java b/backend/src/main/java/kr/touroot/member/service/MemberService.java
index ae81b01f7..b3414dc20 100644
--- a/backend/src/main/java/kr/touroot/member/service/MemberService.java
+++ b/backend/src/main/java/kr/touroot/member/service/MemberService.java
@@ -1,8 +1,10 @@
 package kr.touroot.member.service;
 
+import java.util.Objects;
 import kr.touroot.authentication.infrastructure.PasswordEncryptor;
 import kr.touroot.global.auth.dto.MemberAuth;
 import kr.touroot.global.exception.BadRequestException;
+import kr.touroot.image.infrastructure.AwsS3Provider;
 import kr.touroot.member.domain.Member;
 import kr.touroot.member.dto.request.MemberRequest;
 import kr.touroot.member.dto.request.ProfileUpdateRequest;
@@ -18,6 +20,7 @@ public class MemberService {
 
     private final MemberRepository memberRepository;
     private final PasswordEncryptor passwordEncryptor;
+    private final AwsS3Provider s3Provider;
 
     @Transactional(readOnly = true)
     public Member getMemberById(Long memberId) {
@@ -54,7 +57,14 @@ private void validateNicknameDuplication(String nickname) {
     @Transactional
     public ProfileResponse updateProfile(ProfileUpdateRequest request, MemberAuth memberAuth) {
         Member member = getMemberById(memberAuth.memberId());
-        member.changeNickname(request.nickname());
+        String requestProfileImageUrl = request.profileImageUrl();
+        if (!Objects.equals(request.profileImageUrl(), member.getProfileImageUrl())) {
+            requestProfileImageUrl = s3Provider.copyImageToPermanentStorage(request.profileImageUrl());
+        }
+        member.update(request.nickname(), requestProfileImageUrl);
+
+//        Member member = getMemberById(memberAuth.memberId());
+//        member.changeNickname(request.nickname());
 
         return ProfileResponse.from(member);
     }
diff --git a/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java b/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
index 4df72d07e..93051ab46 100644
--- a/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
+++ b/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
@@ -4,8 +4,11 @@
 
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import java.util.List;
 import kr.touroot.authentication.infrastructure.JwtTokenProvider;
 import kr.touroot.global.AcceptanceTest;
+import kr.touroot.image.domain.ImageFile;
+import kr.touroot.image.infrastructure.AwsS3Provider;
 import kr.touroot.member.domain.Member;
 import kr.touroot.member.dto.request.ProfileUpdateRequest;
 import kr.touroot.travelogue.helper.TravelogueTestHelper;
@@ -17,6 +20,8 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.web.server.LocalServerPort;
 import org.springframework.http.HttpHeaders;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.web.multipart.MultipartFile;
 
 @DisplayName("마이 페이지 컨트롤러")
 @AcceptanceTest
@@ -31,18 +36,21 @@ class MyPageControllerTest {
     private int port;
     private String accessToken;
     private Member member;
+    private final AwsS3Provider s3Provider;
 
     @Autowired
     public MyPageControllerTest(
             DatabaseCleaner databaseCleaner,
             JwtTokenProvider jwtTokenProvider,
             TravelogueTestHelper travelogueTestHelper,
-            TravelPlanTestHelper travelPlanTestHelper
+            TravelPlanTestHelper travelPlanTestHelper,
+            AwsS3Provider s3Provider
     ) {
         this.databaseCleaner = databaseCleaner;
         this.jwtTokenProvider = jwtTokenProvider;
         this.travelogueTestHelper = travelogueTestHelper;
         this.travelPlanTestHelper = travelPlanTestHelper;
+        this.s3Provider = s3Provider;
     }
 
     @BeforeEach
@@ -98,7 +106,12 @@ void readTravelPlans() {
     void updateProfile() {
         // given
         String newNickname = "newNickname";
-        ProfileUpdateRequest request = new ProfileUpdateRequest(newNickname);
+        MultipartFile multipartFile = new MockMultipartFile("file", "image.jpg", "image/jpeg",
+                "image content".getBytes());
+        String newProfileImageUrl = s3Provider.uploadImages(List.of(new ImageFile(multipartFile)))
+                .get(0)
+                .replace("temporary", "images");
+        ProfileUpdateRequest request = new ProfileUpdateRequest(newNickname, newProfileImageUrl);
 
         // when & then
         RestAssured.given().log().all()
@@ -106,9 +119,10 @@ void updateProfile() {
                 .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
                 .body(request)
                 .when().log().all()
-                .patch("/api/v1/member/me/profile")
+                .put("/api/v1/member/me/profile")
                 .then().log().all()
                 .statusCode(200)
-                .body("nickname", is(newNickname));
+                .body("nickname", is(newNickname))
+                .body("profileImageUrl", is(newProfileImageUrl));
     }
 }
diff --git a/backend/src/test/java/kr/touroot/member/domain/MemberTest.java b/backend/src/test/java/kr/touroot/member/domain/MemberTest.java
index 26c1ca872..94254320a 100644
--- a/backend/src/test/java/kr/touroot/member/domain/MemberTest.java
+++ b/backend/src/test/java/kr/touroot/member/domain/MemberTest.java
@@ -94,7 +94,7 @@ void createMemberWithInvalidProfileImageUrl(String invalidProfileImageUrl) {
     @Test
     void changeNicknameWithValidData() {
         Member member = new Member(VALID_SOCIAl_ID, VALID_NICKNAME, VALID_PROFILE_IMAGE_URL, KAKAO);
-        assertThatCode(() -> member.changeNickname(VALID_NICKNAME + "a"))
+        assertThatCode(() -> member.update(VALID_NICKNAME + "a", VALID_PROFILE_IMAGE_URL))
                 .doesNotThrowAnyException();
     }
 
@@ -103,7 +103,7 @@ void changeNicknameWithValidData() {
     @NullAndEmptySource()
     void changeNicknameWithOrEmpty(String nullOrEmptyNickname) {
         Member member = new Member(VALID_SOCIAl_ID, VALID_NICKNAME, VALID_PROFILE_IMAGE_URL, KAKAO);
-        assertThatThrownBy(() -> member.changeNickname(nullOrEmptyNickname))
+        assertThatThrownBy(() -> member.update(nullOrEmptyNickname, VALID_PROFILE_IMAGE_URL))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("닉네임은 비어 있을 수 없습니다");
     }
@@ -113,7 +113,7 @@ void changeNicknameWithOrEmpty(String nullOrEmptyNickname) {
     @ValueSource(strings = {"21-length-nicknameeee", "22-length-nicknameeeee"})
     void changeNicknameWithInvalidLength(String invalidLengthNickname) {
         Member member = new Member(VALID_SOCIAl_ID, VALID_NICKNAME, VALID_PROFILE_IMAGE_URL, KAKAO);
-        assertThatThrownBy(() -> member.changeNickname(invalidLengthNickname))
+        assertThatThrownBy(() -> member.update(invalidLengthNickname, VALID_PROFILE_IMAGE_URL))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("닉네임은 1자 이상, 20자 이하여야 합니다");
     }
diff --git a/backend/src/test/java/kr/touroot/member/service/MemberServiceTest.java b/backend/src/test/java/kr/touroot/member/service/MemberServiceTest.java
index b1a16b682..6faea26e5 100644
--- a/backend/src/test/java/kr/touroot/member/service/MemberServiceTest.java
+++ b/backend/src/test/java/kr/touroot/member/service/MemberServiceTest.java
@@ -4,11 +4,16 @@
 import static kr.touroot.member.fixture.MemberRequestFixture.VALID_MEMBER;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertAll;
 
+import java.util.List;
 import kr.touroot.authentication.infrastructure.PasswordEncryptor;
 import kr.touroot.global.ServiceTest;
 import kr.touroot.global.auth.dto.MemberAuth;
+import kr.touroot.global.config.EmbeddedS3Config;
 import kr.touroot.global.exception.BadRequestException;
+import kr.touroot.image.domain.ImageFile;
+import kr.touroot.image.infrastructure.AwsS3Provider;
 import kr.touroot.member.domain.Member;
 import kr.touroot.member.dto.request.MemberRequest;
 import kr.touroot.member.dto.request.ProfileUpdateRequest;
@@ -19,25 +24,31 @@
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Import;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.web.multipart.MultipartFile;
 
 @DisplayName("사용자 서비스")
-@Import(value = {MemberService.class, MemberTestHelper.class, PasswordEncryptor.class})
+@Import(value = {MemberService.class, MemberTestHelper.class, PasswordEncryptor.class, AwsS3Provider.class,
+        EmbeddedS3Config.class})
 @ServiceTest
 class MemberServiceTest {
 
     private final MemberService memberService;
     private final MemberTestHelper testHelper;
     private final DatabaseCleaner databaseCleaner;
+    private final AwsS3Provider s3Provider;
 
     @Autowired
     public MemberServiceTest(
             MemberService memberService,
             MemberTestHelper testHelper,
-            DatabaseCleaner databaseCleaner
+            DatabaseCleaner databaseCleaner,
+            AwsS3Provider s3Provider
     ) {
         this.memberService = memberService;
         this.testHelper = testHelper;
         this.databaseCleaner = databaseCleaner;
+        this.s3Provider = s3Provider;
     }
 
     @BeforeEach
@@ -99,11 +110,21 @@ void createMemberWithDuplicatedNickname() {
     void updateProfile() {
         Member member = testHelper.persistMember();
         MemberAuth memberAuth = new MemberAuth(member.getId());
-        ProfileUpdateRequest request = new ProfileUpdateRequest("newNickname");
+        String newNickname = "newNickname";
+        MultipartFile multipartFile = new MockMultipartFile("file", "image.jpg", "image/jpeg",
+                "image content".getBytes());
+        String newProfileImageUrl = s3Provider.uploadImages(List.of(new ImageFile(multipartFile)))
+                .get(0)
+                .replace("temporary", "images");
+        ProfileUpdateRequest request = new ProfileUpdateRequest(newNickname, newProfileImageUrl);
 
         memberService.updateProfile(request, memberAuth);
 
-        assertThat(memberService.getMemberById(member.getId()).getNickname())
-                .isEqualTo("newNickname");
+        assertAll(
+                () -> assertThat(memberService.getMemberById(member.getId()).getNickname())
+                        .isEqualTo(newNickname),
+                () -> assertThat(memberService.getMemberById(member.getId()).getProfileImageUrl())
+                        .isEqualTo(newProfileImageUrl)
+        );
     }
 }
diff --git a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
index b0372da0e..655fda9ee 100644
--- a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
@@ -9,7 +9,9 @@
 import kr.touroot.authentication.infrastructure.PasswordEncryptor;
 import kr.touroot.global.ServiceTest;
 import kr.touroot.global.auth.dto.MemberAuth;
+import kr.touroot.global.config.EmbeddedS3Config;
 import kr.touroot.global.exception.BadRequestException;
+import kr.touroot.image.infrastructure.AwsS3Provider;
 import kr.touroot.member.domain.Member;
 import kr.touroot.member.service.MemberService;
 import kr.touroot.travelplan.domain.TravelPlan;
@@ -33,7 +35,9 @@
         TravelPlanService.class,
         MemberService.class,
         PasswordEncryptor.class,
-        TravelPlanTestHelper.class
+        TravelPlanTestHelper.class,
+        AwsS3Provider.class,
+        EmbeddedS3Config.class
 })
 @ServiceTest
 class TravelPlanFacadeServiceTest {

From efeb765e7b64496cb679175fde9b0200a1f5531a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Mon, 14 Oct 2024 16:41:55 +0900
Subject: [PATCH 02/13] =?UTF-8?q?feat:=20OSIV=20=EC=98=B5=EC=85=98=20?=
 =?UTF-8?q?=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94=20(#532)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/src/main/resources/application.yml      | 4 ++++
 backend/src/test/resources/application-test.yml | 1 +
 2 files changed, 5 insertions(+)

diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
index fb5121d8c..f551c4692 100644
--- a/backend/src/main/resources/application.yml
+++ b/backend/src/main/resources/application.yml
@@ -32,6 +32,10 @@ management:
         include: info, health, metrics
       base-path: ENC(zc5tP1eNIEjv3uN5Kuih7wlo5zILgWxq)
     enabled-by-default: false
+
+spring:
+  jpa:
+    open-in-view: false
 ---
 # local profile
 spring:
diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml
index 4436b5d28..bad48d5b4 100644
--- a/backend/src/test/resources/application-test.yml
+++ b/backend/src/test/resources/application-test.yml
@@ -39,6 +39,7 @@ spring:
     hibernate:
       ddl-auto: create
     defer-datasource-initialization: true
+    open-in-view: false
   sql:
     init:
       mode: never

From 933fc438d20358a9235eb8f12957ee85c07f27ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Sun, 20 Oct 2024 21:04:21 +0900
Subject: [PATCH 03/13] =?UTF-8?q?[Feature]=20-=20=EB=82=98=EB=9D=BC=20?=
 =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20?=
 =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#544)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../travelogue/domain/TravelogueCountry.java  |  47 ++++
 .../travelogue/domain/search/CountryCode.java | 261 ++++++++++++++++++
 .../travelogue/domain/search/SearchType.java  |   2 +-
 .../dto/request/TraveloguePlaceRequest.java   |   5 +-
 .../dto/request/TravelogueSearchRequest.java  |   2 +-
 .../TravelogueCountryRepository.java          |  15 +
 .../query/TravelogueQueryRepository.java      |   3 +
 .../query/TravelogueQueryRepositoryImpl.java  |  19 +-
 .../service/TravelogueCountryService.java     |  52 ++++
 .../service/TravelogueFacadeService.java      |   4 +
 .../travelogue/service/TravelogueService.java |   9 +
 .../mysql/V6_add_travelogue_country.sql       |  13 +
 .../domain/search/CountryCodeTest.java        |  31 +++
 .../fixture/TravelogueCountryFixture.java     |  18 ++
 .../fixture/TravelogueRequestFixture.java     |   6 +-
 .../helper/TravelogueTestHelper.java          |  16 +-
 .../service/TravelogueFacadeServiceTest.java  |  14 +
 17 files changed, 510 insertions(+), 7 deletions(-)
 create mode 100644 backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
 create mode 100644 backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
 create mode 100644 backend/src/main/java/kr/touroot/travelogue/repository/TravelogueCountryRepository.java
 create mode 100644 backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
 create mode 100644 backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql
 create mode 100644 backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
 create mode 100644 backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java

diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
new file mode 100644
index 000000000..01913662c
--- /dev/null
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
@@ -0,0 +1,47 @@
+package kr.touroot.travelogue.domain;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import kr.touroot.travelogue.domain.search.CountryCode;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@EqualsAndHashCode(of = "id", callSuper = false)
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+@Entity
+public class TravelogueCountry {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @JoinColumn(nullable = false)
+    @ManyToOne(fetch = FetchType.LAZY)
+    private Travelogue travelogue;
+
+    @Column(nullable = false)
+    @Enumerated(EnumType.STRING)
+    private CountryCode countryCode;
+
+    @Column(nullable = false)
+    private Long count;
+
+    public TravelogueCountry(Travelogue travelogue, CountryCode countryCode, Long count) {
+        this.travelogue = travelogue;
+        this.countryCode = countryCode;
+        this.count = count;
+    }
+}
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
new file mode 100644
index 000000000..6ec439a9a
--- /dev/null
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
@@ -0,0 +1,261 @@
+package kr.touroot.travelogue.domain.search;
+
+import java.util.Arrays;
+import java.util.Set;
+import kr.touroot.global.exception.BadRequestException;
+
+public enum CountryCode {
+
+    AF(Set.of("아프가니스탄")),
+    AL(Set.of("알바니아")),
+    DZ(Set.of("알제리")),
+    AS(Set.of("아메리칸 사모아")),
+    AD(Set.of("안도라")),
+    AO(Set.of("앙골라")),
+    AI(Set.of("앵귈라")),
+    AQ(Set.of("남극")),
+    AG(Set.of("앤티가 바부다")),
+    AR(Set.of("아르헨티나")),
+    AM(Set.of("아르메니아")),
+    AW(Set.of("아루바")),
+    AU(Set.of("호주")),
+    AT(Set.of("오스트리아")),
+    AZ(Set.of("아제르바이잔")),
+    BS(Set.of("바하마")),
+    BH(Set.of("바레인")),
+    BD(Set.of("방글라데시")),
+    BB(Set.of("바베이도스")),
+    BY(Set.of("벨라루스")),
+    BE(Set.of("벨기에")),
+    BZ(Set.of("벨리즈")),
+    BJ(Set.of("베냉")),
+    BM(Set.of("버뮤다")),
+    BT(Set.of("부탄")),
+    BO(Set.of("볼리비아")),
+    BA(Set.of("보스니아 헤르체고비나")),
+    BW(Set.of("보츠와나")),
+    BV(Set.of("부베섬")),
+    BR(Set.of("브라질")),
+    IO(Set.of("영국령 인도양 지역")),
+    VG(Set.of("영국령 버진 아일랜드")),
+    BN(Set.of("브루나이")),
+    BG(Set.of("불가리아")),
+    BF(Set.of("부르키나파소")),
+    BI(Set.of("부룬디")),
+    KH(Set.of("캄보디아")),
+    CM(Set.of("카메룬")),
+    CA(Set.of("캐나다")),
+    CV(Set.of("카보베르데")),
+    KY(Set.of("케이맨 제도")),
+    CF(Set.of("중앙아프리카 공화국")),
+    TD(Set.of("차드")),
+    CL(Set.of("칠레")),
+    CN(Set.of("중국")),
+    CX(Set.of("크리스마스 섬")),
+    CC(Set.of("코코스 제도")),
+    CO(Set.of("콜롬비아")),
+    KM(Set.of("코모로")),
+    CD(Set.of("콩고 민주공화국")),
+    CG(Set.of("콩고 공화국")),
+    CK(Set.of("쿡 제도")),
+    CR(Set.of("코스타리카")),
+    CI(Set.of("코트디부아르")),
+    CU(Set.of("쿠바")),
+    CY(Set.of("키프로스")),
+    CZ(Set.of("체코")),
+    DK(Set.of("덴마크")),
+    DJ(Set.of("지부티")),
+    DM(Set.of("도미니카")),
+    DO(Set.of("도미니카 공화국")),
+    EC(Set.of("에콰도르")),
+    EG(Set.of("이집트")),
+    SV(Set.of("엘살바도르")),
+    GQ(Set.of("적도기니")),
+    ER(Set.of("에리트레아")),
+    EE(Set.of("에스토니아")),
+    ET(Set.of("에티오피아")),
+    FO(Set.of("페로 제도")),
+    FK(Set.of("포클랜드 제도")),
+    FJ(Set.of("피지")),
+    FI(Set.of("핀란드")),
+    FR(Set.of("프랑스")),
+    GF(Set.of("프랑스령 기아나")),
+    PF(Set.of("프랑스령 폴리네시아")),
+    TF(Set.of("프랑스령 남부 지역")),
+    GA(Set.of("가봉")),
+    GM(Set.of("감비아")),
+    GE(Set.of("조지아")),
+    DE(Set.of("독일")),
+    GH(Set.of("가나")),
+    GI(Set.of("지브롤터")),
+    GR(Set.of("그리스")),
+    GL(Set.of("그린란드")),
+    GD(Set.of("그레나다")),
+    GP(Set.of("과들루프")),
+    GU(Set.of("괌")),
+    GT(Set.of("과테말라")),
+    GN(Set.of("기니")),
+    GW(Set.of("기니비사우")),
+    GY(Set.of("가이아나")),
+    HT(Set.of("아이티")),
+    HM(Set.of("허드 맥도널드 제도")),
+    VA(Set.of("바티칸")),
+    HN(Set.of("온두라스")),
+    HK(Set.of("홍콩")),
+    HR(Set.of("크로아티아")),
+    HU(Set.of("헝가리")),
+    IS(Set.of("아이슬란드")),
+    IN(Set.of("인도")),
+    ID(Set.of("인도네시아")),
+    IR(Set.of("이란")),
+    IQ(Set.of("이라크")),
+    IE(Set.of("아일랜드")),
+    IL(Set.of("이스라엘")),
+    IT(Set.of("이탈리아")),
+    JM(Set.of("자메이카")),
+    JP(Set.of("일본")),
+    JO(Set.of("요르단")),
+    KZ(Set.of("카자흐스탄")),
+    KE(Set.of("케냐")),
+    KI(Set.of("키리바시")),
+    KP(Set.of("북한", "조선민주주의인민공화국")),
+    KR(Set.of("대한민국", "한국")),
+    KW(Set.of("쿠웨이트")),
+    KG(Set.of("키르기스스탄")),
+    LA(Set.of("라오스")),
+    LV(Set.of("라트비아")),
+    LB(Set.of("레바논")),
+    LS(Set.of("레소토")),
+    LR(Set.of("라이베리아")),
+    LY(Set.of("리비아")),
+    LI(Set.of("리히텐슈타인")),
+    LT(Set.of("리투아니아")),
+    LU(Set.of("룩셈부르크")),
+    MO(Set.of("마카오")),
+    MK(Set.of("북마케도니아")),
+    MG(Set.of("마다가스카르")),
+    MW(Set.of("말라위")),
+    MY(Set.of("말레이시아")),
+    MV(Set.of("몰디브")),
+    ML(Set.of("말리")),
+    MT(Set.of("몰타")),
+    MH(Set.of("마셜제도")),
+    MQ(Set.of("마르티니크")),
+    MR(Set.of("모리타니")),
+    MU(Set.of("모리셔스")),
+    YT(Set.of("마요트")),
+    MX(Set.of("멕시코")),
+    FM(Set.of("미크로네시아")),
+    MD(Set.of("몰도바")),
+    MC(Set.of("모나코")),
+    MN(Set.of("몽골")),
+    MS(Set.of("몬트세랫")),
+    MA(Set.of("모로코")),
+    MZ(Set.of("모잠비크")),
+    MM(Set.of("미얀마")),
+    NA(Set.of("나미비아")),
+    NR(Set.of("나우루")),
+    NP(Set.of("네팔")),
+    AN(Set.of("네덜란드 안틸레스")),
+    NL(Set.of("네덜란드")),
+    NC(Set.of("뉴칼레도니아")),
+    NZ(Set.of("뉴질랜드")),
+    NI(Set.of("니카라과")),
+    NE(Set.of("니제르")),
+    NG(Set.of("나이지리아")),
+    NU(Set.of("니우에")),
+    NF(Set.of("노퍽 섬")),
+    MP(Set.of("북마리아나 제도")),
+    NO(Set.of("노르웨이")),
+    OM(Set.of("오만")),
+    PK(Set.of("파키스탄")),
+    PW(Set.of("팔라우")),
+    PS(Set.of("팔레스타인")),
+    PA(Set.of("파나마")),
+    PG(Set.of("파푸아 뉴기니")),
+    PY(Set.of("파라과이")),
+    PE(Set.of("페루")),
+    PH(Set.of("필리핀")),
+    PN(Set.of("핏케언 제도")),
+    PL(Set.of("폴란드")),
+    PT(Set.of("포르투갈")),
+    PR(Set.of("푸에르토리코")),
+    QA(Set.of("카타르")),
+    RE(Set.of("레위니옹")),
+    RO(Set.of("루마니아")),
+    RU(Set.of("러시아")),
+    RW(Set.of("르완다")),
+    SH(Set.of("세인트헬레나")),
+    KN(Set.of("세인트키츠 네비스")),
+    LC(Set.of("세인트루시아")),
+    PM(Set.of("세인트피에르 미클롱")),
+    VC(Set.of("세인트빈센트 그레나딘")),
+    WS(Set.of("사모아")),
+    SM(Set.of("산마리노")),
+    ST(Set.of("상투메 프린시페")),
+    SA(Set.of("사우디아라비아")),
+    SN(Set.of("세네갈")),
+    CS(Set.of("세르비아 몬테네그로")),
+    SC(Set.of("세이셸")),
+    SL(Set.of("시에라리온")),
+    SG(Set.of("싱가포르")),
+    SK(Set.of("슬로바키아")),
+    SI(Set.of("슬로베니아")),
+    SB(Set.of("솔로몬 제도")),
+    SO(Set.of("소말리아")),
+    ZA(Set.of("남아프리카 공화국", "남아공")),
+    GS(Set.of("사우스조지아 사우스샌드위치 제도")),
+    ES(Set.of("스페인", "에스파냐")),
+    LK(Set.of("스리랑카")),
+    SD(Set.of("수단")),
+    SR(Set.of("수리남")),
+    SJ(Set.of("스발바르 얀마웬")),
+    SZ(Set.of("스와질란드", "에스와티니")),
+    SE(Set.of("스웨덴")),
+    CH(Set.of("스위스")),
+    SY(Set.of("시리아")),
+    TW(Set.of("대만", "타이완")),
+    TJ(Set.of("타지키스탄")),
+    TZ(Set.of("탄자니아")),
+    TH(Set.of("태국")),
+    TL(Set.of("동티모르")),
+    TG(Set.of("토고")),
+    TK(Set.of("토켈라우")),
+    TO(Set.of("통가")),
+    TT(Set.of("트리니다드 토바고")),
+    TN(Set.of("튀니지")),
+    TR(Set.of("터키", "튀르키예")),
+    TM(Set.of("투르크메니스탄")),
+    TC(Set.of("터크스 케이커스 제도")),
+    TV(Set.of("투발루")),
+    VI(Set.of("미국령 버진 아일랜드")),
+    UG(Set.of("우간다")),
+    UA(Set.of("우크라이나")),
+    AE(Set.of("아랍에미리트")),
+    GB(Set.of("영국")),
+    UM(Set.of("미국령 외곽 소섬")),
+    US(Set.of("미국")),
+    UY(Set.of("우루과이")),
+    UZ(Set.of("우즈베키스탄")),
+    VU(Set.of("바누아투")),
+    VE(Set.of("베네수엘라")),
+    VN(Set.of("베트남")),
+    WF(Set.of("왈리스 푸투나")),
+    EH(Set.of("서사하라")),
+    YE(Set.of("예멘")),
+    ZM(Set.of("잠비아")),
+    ZW(Set.of("짐바브웨"));
+
+    private final Set<String> names;
+
+    CountryCode(Set<String> names) {
+        this.names = names;
+    }
+
+    public static CountryCode findByName(String name) {
+        return Arrays.stream(values())
+                .filter(code -> code.names.contains(name))
+                .findFirst()
+                .orElseThrow(() -> new BadRequestException("국가 이름을 찾을 수 없습니다."));
+    }
+}
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
index 299cbd76f..804bc6321 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
@@ -3,7 +3,7 @@
 import java.util.Arrays;
 
 public enum SearchType {
-    TITLE, AUTHOR;
+    TITLE, AUTHOR, COUNTRY;
 
     public static SearchType from(String searchType) {
         return Arrays.stream(SearchType.values())
diff --git a/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java b/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
index ad48e8fea..8bd4c8988 100644
--- a/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
+++ b/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
@@ -26,7 +26,10 @@ public record TraveloguePlaceRequest(
         @NotNull(message = "여행기 장소 사진은 null일 수 없습니다.")
         @Size(message = "여행기 장소 사진은 최대 10개입니다.", max = 10)
         @Valid
-        List<TraveloguePhotoRequest> photoUrls
+        List<TraveloguePhotoRequest> photoUrls,
+        @Schema(description = "여행기 장소 국가 코드")
+        @NotBlank(message = "여행기 장소 국가 코드는 비어있을 수 없습니다.")
+        String countryCode
 ) {
 
     public TraveloguePlace toTraveloguePlace(int order, TravelogueDay travelogueDay) {
diff --git a/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java b/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
index 9017c06cc..c03c6003e 100644
--- a/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
+++ b/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
@@ -9,7 +9,7 @@ public record TravelogueSearchRequest(
         @NotBlank(message = "검색어는 2글자 이상이어야 합니다.")
         @Size(min = 2, message = "검색어는 2글자 이상이어야 합니다.")
         String keyword,
-        @Schema(description = "검색 키워드 종류 (TITLE, AUTHOR)", example = "TITLE")
+        @Schema(description = "검색 키워드 종류 (TITLE, AUTHOR, COUNTRY)", example = "TITLE")
         @NotBlank(message = "검색 키워드 종류는 필수입니다.")
         String searchType
 ) {
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueCountryRepository.java b/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueCountryRepository.java
new file mode 100644
index 000000000..4a420ecbd
--- /dev/null
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueCountryRepository.java
@@ -0,0 +1,15 @@
+package kr.touroot.travelogue.repository;
+
+import java.util.List;
+import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueCountry;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface TravelogueCountryRepository extends JpaRepository<TravelogueCountry, Long> {
+
+    List<TravelogueCountry> findAllByTravelogue(Travelogue travelogue);
+
+    void deleteAllByTravelogue(Travelogue travelogue);
+}
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
index 7d4eae28d..853c9ca63 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
@@ -2,6 +2,7 @@
 
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
+import kr.touroot.travelogue.domain.search.CountryCode;
 import kr.touroot.travelogue.domain.search.SearchCondition;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
@@ -10,5 +11,7 @@ public interface TravelogueQueryRepository {
 
     Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pageable pageable);
 
+    Page<Travelogue> findByKeywordAndCountryCode(CountryCode countryCode, Pageable pageable);
+
     Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable);
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
index 377fd2e5d..d47be6d55 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
@@ -1,17 +1,19 @@
 package kr.touroot.travelogue.repository.query;
 
 import static kr.touroot.travelogue.domain.QTravelogue.travelogue;
+import static kr.touroot.travelogue.domain.QTravelogueCountry.travelogueCountry;
 import static kr.touroot.travelogue.domain.QTravelogueTag.travelogueTag;
 
 import com.querydsl.core.types.Order;
 import com.querydsl.core.types.OrderSpecifier;
 import com.querydsl.core.types.dsl.Expressions;
+import com.querydsl.core.types.dsl.StringPath;
 import com.querydsl.jpa.impl.JPAQuery;
 import com.querydsl.jpa.impl.JPAQueryFactory;
 import java.util.List;
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
-import com.querydsl.core.types.dsl.StringPath;
+import kr.touroot.travelogue.domain.search.CountryCode;
 import kr.touroot.travelogue.domain.search.SearchCondition;
 import kr.touroot.travelogue.domain.search.SearchType;
 import lombok.RequiredArgsConstructor;
@@ -45,6 +47,21 @@ public Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pa
         return new PageImpl<>(results, pageable, results.size());
     }
 
+    @Override
+    public Page<Travelogue> findByKeywordAndCountryCode(CountryCode countryCode, Pageable pageable) {
+        List<Travelogue> results = jpaQueryFactory.select(travelogue)
+                .from(travelogue)
+                .join(travelogueCountry)
+                .on(travelogue.id.eq(travelogueCountry.travelogue.id))
+                .where(travelogueCountry.countryCode.eq(countryCode))
+                .orderBy(travelogueCountry.count.desc())
+                .offset(pageable.getOffset())
+                .limit(pageable.getPageSize())
+                .fetch();
+
+        return new PageImpl<>(results, pageable, results.size());
+    }
+
     private StringPath getTargetField(SearchType searchType) {
         if (SearchType.AUTHOR.equals(searchType)) {
             return travelogue.author.nickname;
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
new file mode 100644
index 000000000..e4fa860ed
--- /dev/null
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
@@ -0,0 +1,52 @@
+package kr.touroot.travelogue.service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueCountry;
+import kr.touroot.travelogue.domain.search.CountryCode;
+import kr.touroot.travelogue.dto.request.TravelogueRequest;
+import kr.touroot.travelogue.repository.TravelogueCountryRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Service
+public class TravelogueCountryService {
+
+    private final TravelogueCountryRepository travelogueCountryRepository;
+
+    @Transactional(readOnly = true)
+    public List<TravelogueCountry> readCountryByTravelogue(Travelogue travelogue) {
+        return travelogueCountryRepository.findAllByTravelogue(travelogue);
+    }
+
+    @Transactional
+    public void createTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
+        Map<CountryCode, Long> countryCounts = countCountries(request);
+
+        countryCounts.forEach((countryCode, count) -> travelogueCountryRepository.save(
+                new TravelogueCountry(travelogue, countryCode, count)));
+    }
+
+    private Map<CountryCode, Long> countCountries(TravelogueRequest request) {
+        return request.days().stream()
+                .flatMap(day -> day.places().stream())
+                .map(place -> CountryCode.valueOf(place.countryCode()))
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+    }
+
+    @Transactional
+    public void updateTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
+        deleteAllByTravelogue(travelogue);
+        createTravelogueCountries(travelogue, request);
+    }
+
+    @Transactional
+    public void deleteAllByTravelogue(Travelogue travelogue) {
+        travelogueCountryRepository.deleteAllByTravelogue(travelogue);
+    }
+}
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
index 8c919b598..47ab457c5 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
@@ -28,6 +28,7 @@ public class TravelogueFacadeService {
     private final TravelogueImagePerpetuationService travelogueImagePerpetuationService;
     private final TravelogueTagService travelogueTagService;
     private final TravelogueLikeService travelogueLikeService;
+    private final TravelogueCountryService travelogueCountryService;
     private final MemberService memberService;
 
     @Transactional
@@ -36,6 +37,7 @@ public TravelogueCreateResponse createTravelogue(MemberAuth member, TravelogueRe
         Travelogue travelogue = travelogueService.save(request.toTravelogue(author));
         travelogueImagePerpetuationService.copyTravelogueImagesToPermanentStorage(travelogue);
         travelogueTagService.createTravelogueTags(travelogue, request.tags());
+        travelogueCountryService.createTravelogueCountries(travelogue, request);
 
         return TravelogueCreateResponse.from(travelogue);
     }
@@ -89,6 +91,7 @@ public TravelogueResponse updateTravelogue(Long id, MemberAuth member, Travelogu
         Travelogue updated = travelogueService.update(id, author, updateRequest);
         travelogueImagePerpetuationService.copyTravelogueImagesToPermanentStorage(updated);
         List<TravelogueTag> travelogueTags = travelogueTagService.updateTravelogueTag(updated, updateRequest.tags());
+        travelogueCountryService.updateTravelogueCountries(updated, updateRequest);
 
         boolean isLikedFromAccessor = travelogueLikeService.existByTravelogueAndMember(updated, author);
         return TravelogueResponse.of(updated, travelogueTags, isLikedFromAccessor);
@@ -101,6 +104,7 @@ public void deleteTravelogueById(Long id, MemberAuth member) {
 
         travelogueTagService.deleteAllByTravelogue(travelogue);
         travelogueLikeService.deleteAllByTravelogue(travelogue);
+        travelogueCountryService.deleteAllByTravelogue(travelogue);
         travelogueService.delete(travelogue, author);
     }
 
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
index 4a42a7ef8..eb67a40be 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
@@ -5,6 +5,7 @@
 import kr.touroot.member.domain.Member;
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
+import kr.touroot.travelogue.domain.search.CountryCode;
 import kr.touroot.travelogue.domain.search.SearchCondition;
 import kr.touroot.travelogue.domain.search.SearchType;
 import kr.touroot.travelogue.dto.request.TravelogueRequest;
@@ -43,11 +44,19 @@ public Page<Travelogue> findAllByMember(Member member, Pageable pageable) {
     @Transactional(readOnly = true)
     public Page<Travelogue> findByKeyword(TravelogueSearchRequest request, Pageable pageable) {
         SearchType searchType = SearchType.from(request.searchType());
+        if (searchType == SearchType.COUNTRY) {
+            return findByKeywordAndCountryCode(request.keyword(), pageable);
+        }
         SearchCondition searchCondition = new SearchCondition(request.keyword(), searchType);
 
         return travelogueQueryRepository.findByKeywordAndSearchType(searchCondition, pageable);
     }
 
+    private Page<Travelogue> findByKeywordAndCountryCode(String keyword, Pageable pageable) {
+        CountryCode countryCode = CountryCode.findByName(keyword);
+        return travelogueQueryRepository.findByKeywordAndCountryCode(countryCode, pageable);
+    }
+
     @Transactional(readOnly = true)
     public Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable) {
         if (filter.isEmptyCondition()) {
diff --git a/backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql b/backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql
new file mode 100644
index 000000000..ea7607840
--- /dev/null
+++ b/backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql
@@ -0,0 +1,13 @@
+CREATE TABLE travelogue_country
+(
+    id            BIGINT      NOT NULL AUTO_INCREMENT,
+    travelogue_id BIGINT      NOT NULL,
+    country_code  VARCHAR(50) NOT NULL,
+    count         INT         NOT NULL,
+    PRIMARY KEY (id)
+);
+
+ALTER TABLE travelogue_country
+    ADD CONSTRAINT fk_travelogue_country_travelogue_id FOREIGN KEY (travelogue_id) REFERENCES travelogue (id);
+
+CREATE INDEX idx_country_code_count ON travelogue_country (country_code, count);
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
new file mode 100644
index 000000000..6a268d0a3
--- /dev/null
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
@@ -0,0 +1,31 @@
+package kr.touroot.travelogue.domain.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import kr.touroot.global.exception.BadRequestException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+class CountryCodeTest {
+
+    @DisplayName("국가 이름으로 찾으면 국가 코드를 반환한다.")
+    @ValueSource(strings = {"한국", "대한민국"})
+    @ParameterizedTest
+    void findByName(String name) {
+        CountryCode code = CountryCode.findByName(name);
+
+        assertThat(code)
+                .isEqualTo(CountryCode.KR);
+    }
+
+    @DisplayName("없는 나라 이름으로 찾으면 예외로 처리한다.")
+    @Test
+    void findByNonCountryName() {
+        assertThatThrownBy(() -> CountryCode.findByName("미역국"))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("국가 이름을 찾을 수 없습니다.");
+    }
+}
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java
new file mode 100644
index 000000000..767b8fa56
--- /dev/null
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java
@@ -0,0 +1,18 @@
+package kr.touroot.travelogue.fixture;
+
+import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueCountry;
+import kr.touroot.travelogue.domain.search.CountryCode;
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public enum TravelogueCountryFixture {
+    TRAVELOGUE_COUNTRY(CountryCode.KR, 1L);
+
+    private final CountryCode countryCode;
+    private final Long count;
+
+    public TravelogueCountry create(Travelogue travelogue) {
+        return new TravelogueCountry(travelogue, countryCode, count);
+    }
+}
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
index f0b8f8871..d38b3bc86 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
@@ -54,7 +54,8 @@ public static List<TraveloguePlaceRequest> getTraveloguePlaceRequests(List<Trave
                 "함덕 해수욕장",
                 getTraveloguePositionRequest(),
                 "에메랄드 빛 해변",
-                photos
+                photos,
+                "KR"
         ));
     }
 
@@ -63,7 +64,8 @@ public static List<TraveloguePlaceRequest> getUpdateTraveloguePlaceRequests(List
                 "함덕 해수욕장",
                 getTraveloguePositionRequest(),
                 "에메랄드 빛 해변은 해외 휴양지와 견줘도 밀리지 않습니다.",
-                photos
+                photos,
+                "KR"
         ));
     }
 
diff --git a/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java b/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
index ccfd0411a..60a157a9d 100644
--- a/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
+++ b/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
@@ -1,5 +1,6 @@
 package kr.touroot.travelogue.helper;
 
+import static kr.touroot.travelogue.fixture.TravelogueCountryFixture.TRAVELOGUE_COUNTRY;
 import static kr.touroot.travelogue.fixture.TravelogueDayFixture.TRAVELOGUE_DAY;
 import static kr.touroot.travelogue.fixture.TravelogueFixture.TRAVELOGUE;
 import static kr.touroot.travelogue.fixture.TraveloguePhotoFixture.TRAVELOGUE_PHOTO;
@@ -14,11 +15,13 @@
 import kr.touroot.tag.fixture.TagFixture;
 import kr.touroot.tag.repository.TagRepository;
 import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueCountry;
 import kr.touroot.travelogue.domain.TravelogueDay;
 import kr.touroot.travelogue.domain.TravelogueLike;
 import kr.touroot.travelogue.domain.TraveloguePhoto;
 import kr.touroot.travelogue.domain.TraveloguePlace;
 import kr.touroot.travelogue.domain.TravelogueTag;
+import kr.touroot.travelogue.repository.TravelogueCountryRepository;
 import kr.touroot.travelogue.repository.TravelogueDayRepository;
 import kr.touroot.travelogue.repository.TravelogueLikeRepository;
 import kr.touroot.travelogue.repository.TraveloguePhotoRepository;
@@ -39,6 +42,7 @@ public class TravelogueTestHelper {
     private final TagRepository tagRepository;
     private final TravelogueTagRepository travelogueTagRepository;
     private final TravelogueLikeRepository travelogueLikeRepository;
+    private final TravelogueCountryRepository travelogueCountryRepository;
 
     @Autowired
     public TravelogueTestHelper(
@@ -49,7 +53,8 @@ public TravelogueTestHelper(
             MemberRepository memberRepository,
             TagRepository tagRepository,
             TravelogueTagRepository travelogueTagRepository,
-            TravelogueLikeRepository travelogueLikeRepository
+            TravelogueLikeRepository travelogueLikeRepository,
+            TravelogueCountryRepository travelogueCountryRepository
     ) {
         this.travelogueRepository = travelogueRepository;
         this.travelogueDayRepository = travelogueDayRepository;
@@ -59,6 +64,7 @@ public TravelogueTestHelper(
         this.tagRepository = tagRepository;
         this.travelogueTagRepository = travelogueTagRepository;
         this.travelogueLikeRepository = travelogueLikeRepository;
+        this.travelogueCountryRepository = travelogueCountryRepository;
     }
 
     public void initAllTravelogueTestData() {
@@ -82,6 +88,7 @@ public Travelogue initTravelogueTestData(Member author) {
         Travelogue travelogue = persistTravelogue(author);
         TravelogueDay day = persistTravelogueDay(travelogue);
         TraveloguePlace place = persistTraveloguePlace(day);
+        persistTravelogueCountry(travelogue);
         persistTraveloguePhoto(place);
 
         return travelogue;
@@ -103,6 +110,7 @@ public Travelogue initTravelogueTestDataWithTag(Member author) {
         Travelogue travelogue = persistTravelogue(author);
         TravelogueDay day = persistTravelogueDay(travelogue);
         TraveloguePlace place = persistTraveloguePlace(day);
+        persistTravelogueCountry(travelogue);
         persistTraveloguePhoto(place);
         persisTravelogueTag(travelogue, TagFixture.TAG_1.get());
 
@@ -156,6 +164,12 @@ public TraveloguePlace persistTraveloguePlace(TravelogueDay day) {
         return traveloguePlaceRepository.save(place);
     }
 
+    public TravelogueCountry persistTravelogueCountry(Travelogue travelogue) {
+        TravelogueCountry travelogueCountry = TRAVELOGUE_COUNTRY.create(travelogue);
+
+        return travelogueCountryRepository.save(travelogueCountry);
+    }
+
     public TraveloguePhoto persistTraveloguePhoto(TraveloguePlace place) {
         TraveloguePhoto photo = TRAVELOGUE_PHOTO.create(place);
 
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
index ba0c8820c..99ae5bb92 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
@@ -48,6 +48,7 @@
         TravelogueImagePerpetuationService.class,
         TravelogueTagService.class,
         TravelogueLikeService.class,
+        TravelogueCountryService.class,
         MemberService.class,
         TravelogueTestHelper.class,
         PasswordEncryptor.class,
@@ -197,6 +198,19 @@ void findTraveloguesByAuthorNicknameKeyword() {
         assertThat(searchResults).containsAll(responses);
     }
 
+    @DisplayName("국가 코드를 기반으로 여행기 목록을 조회한다.")
+    @Test
+    void findTraveloguesByCountryCodeKeyword() {
+        testHelper.initAllTravelogueTestData();
+        Page<TravelogueSimpleResponse> responses = TravelogueResponseFixture.getTravelogueSimpleResponses();
+
+        TravelogueSearchRequest searchRequest = new TravelogueSearchRequest("한국", "country");
+        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(searchRequest, pageRequest);
+
+        assertThat(searchResults).containsAll(responses);
+    }
+
     @DisplayName("여행기를 수정할 수 있다.")
     @Test
     void updateTravelogue() {

From 73258c670a9f1680ecdd8a8c17061a83d4b99874 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EB=82=99=ED=97=8C?=
 <95845037+nak-honest@users.noreply.github.com>
Date: Sun, 20 Oct 2024 23:04:33 +0900
Subject: [PATCH 04/13] =?UTF-8?q?[Fix]=20-=20flyway=20=EC=8A=A4=ED=81=AC?=
 =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EB=84=A4=EC=9D=B4?=
 =?UTF-8?q?=EB=B0=8D=20=EA=B7=9C=EC=B9=99=EC=9D=B4=20=EB=A7=9E=EC=A7=80=20?=
 =?UTF-8?q?=EC=95=8A=EC=95=84=20=EC=8B=A4=ED=96=89=EB=90=98=EC=A7=80=20?=
 =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ..._add_travelogue_country.sql => V6__add_travelogue_country.sql} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename backend/src/main/resources/db/migration/mysql/{V6_add_travelogue_country.sql => V6__add_travelogue_country.sql} (100%)

diff --git a/backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql b/backend/src/main/resources/db/migration/mysql/V6__add_travelogue_country.sql
similarity index 100%
rename from backend/src/main/resources/db/migration/mysql/V6_add_travelogue_country.sql
rename to backend/src/main/resources/db/migration/mysql/V6__add_travelogue_country.sql

From c0d4c0beb3e16b64b7d6c82794f16d31d0256b80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EB=82=99=ED=97=8C?=
 <95845037+nak-honest@users.noreply.github.com>
Date: Sun, 20 Oct 2024 23:26:27 +0900
Subject: [PATCH 05/13] =?UTF-8?q?[Fix]=20-=20=EC=8A=A4=ED=82=A4=EB=A7=88?=
 =?UTF-8?q?=EC=99=80=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=82=AC=EC=9D=B4?=
 =?UTF-8?q?=EC=9D=98=20=EC=BB=AC=EB=9F=BC=20=ED=83=80=EC=9E=85=20=EB=B6=88?=
 =?UTF-8?q?=EC=9D=BC=EC=B9=98=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EB=B2=84?=
 =?UTF-8?q?=EA=B7=B8=20=ED=95=B4=EA=B2=B0=20(#549)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/kr/touroot/travelogue/domain/TravelogueCountry.java  | 4 ++--
 .../touroot/travelogue/service/TravelogueCountryService.java  | 2 +-
 .../touroot/travelogue/fixture/TravelogueCountryFixture.java  | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
index 01913662c..503e0b60c 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
@@ -37,9 +37,9 @@ public class TravelogueCountry {
     private CountryCode countryCode;
 
     @Column(nullable = false)
-    private Long count;
+    private Integer count;
 
-    public TravelogueCountry(Travelogue travelogue, CountryCode countryCode, Long count) {
+    public TravelogueCountry(Travelogue travelogue, CountryCode countryCode, Integer count) {
         this.travelogue = travelogue;
         this.countryCode = countryCode;
         this.count = count;
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
index e4fa860ed..62b6de825 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
@@ -29,7 +29,7 @@ public void createTravelogueCountries(Travelogue travelogue, TravelogueRequest r
         Map<CountryCode, Long> countryCounts = countCountries(request);
 
         countryCounts.forEach((countryCode, count) -> travelogueCountryRepository.save(
-                new TravelogueCountry(travelogue, countryCode, count)));
+                new TravelogueCountry(travelogue, countryCode, count.intValue())));
     }
 
     private Map<CountryCode, Long> countCountries(TravelogueRequest request) {
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java
index 767b8fa56..adc7b8d30 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueCountryFixture.java
@@ -13,6 +13,6 @@ public enum TravelogueCountryFixture {
     private final Long count;
 
     public TravelogueCountry create(Travelogue travelogue) {
-        return new TravelogueCountry(travelogue, countryCode, count);
+        return new TravelogueCountry(travelogue, countryCode, count.intValue());
     }
 }

From ff555a3a6789dee40151ef338e03e1ed3cf76e0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EB=82=99=ED=97=8C?=
 <95845037+nak-honest@users.noreply.github.com>
Date: Sun, 20 Oct 2024 23:31:23 +0900
Subject: [PATCH 06/13] =?UTF-8?q?[Feature]=20-=20=EC=9E=90=EC=8B=A0?=
 =?UTF-8?q?=EC=9D=B4=20=EC=A2=8B=EC=95=84=EC=9A=94=EB=A5=BC=20=EB=88=84?=
 =?UTF-8?q?=EB=A5=B8=20=EA=B2=8C=EC=8B=9C=EA=B8=80=EC=9D=84=20=EC=A1=B0?=
 =?UTF-8?q?=ED=9A=8C=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84=20(#540)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat: 내가 좋아요 한 여행기 조회 기능 구현

* test: 내가 좋아요 한 여행기 조회 테스트 코드 추가

* refactor: 다른 dto 와 형식 통일
---
 .../member/controller/MyPageController.java   | 25 +++++++++++++++
 .../response/MyLikeTravelogueResponse.java    | 31 +++++++++++++++++++
 .../member/service/MyPageFacadeService.java   | 13 ++++++++
 .../repository/TravelogueLikeRepository.java  |  4 +++
 .../service/TravelogueLikeService.java        |  7 +++++
 .../controller/MyPageControllerTest.java      | 19 ++++++++++++
 .../service/TravelogueLikeServiceTest.java    | 17 ++++++++++
 7 files changed, 116 insertions(+)
 create mode 100644 backend/src/main/java/kr/touroot/member/dto/response/MyLikeTravelogueResponse.java

diff --git a/backend/src/main/java/kr/touroot/member/controller/MyPageController.java b/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
index d1ff6b989..6ea08a839 100644
--- a/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
+++ b/backend/src/main/java/kr/touroot/member/controller/MyPageController.java
@@ -12,6 +12,7 @@
 import kr.touroot.global.auth.dto.MemberAuth;
 import kr.touroot.global.exception.dto.ExceptionResponse;
 import kr.touroot.member.dto.request.ProfileUpdateRequest;
+import kr.touroot.member.dto.response.MyLikeTravelogueResponse;
 import kr.touroot.member.dto.response.MyTravelogueResponse;
 import kr.touroot.member.dto.response.ProfileResponse;
 import kr.touroot.member.service.MyPageFacadeService;
@@ -103,6 +104,30 @@ public ResponseEntity<Page<PlanResponse>> readTravelPlans(
         return ResponseEntity.ok(data);
     }
 
+    @Operation(summary = "내가 좋아요 한 여행기 조회")
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200",
+                    description = "내가 좋아요 한 여행기 조회에 성공했을 때"
+            ),
+            @ApiResponse(
+                    responseCode = "401",
+                    description = "로그인하지 않은 사용자가 조회를 시도할 때",
+                    content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
+            )
+    })
+    @PageableAsQueryParam
+    @GetMapping("/likes")
+    public ResponseEntity<Page<MyLikeTravelogueResponse>> readLikes(
+            @NotNull MemberAuth memberAuth,
+            @Parameter(hidden = true)
+            @PageableDefault(size = 5, sort = "id", direction = Sort.Direction.DESC)
+            Pageable pageable
+    ) {
+        Page<MyLikeTravelogueResponse> data = myPageFacadeService.readLikes(memberAuth, pageable);
+        return ResponseEntity.ok(data);
+    }
+
     @Operation(summary = "나의 프로필 정보 수정")
     @ApiResponses(value = {
             @ApiResponse(
diff --git a/backend/src/main/java/kr/touroot/member/dto/response/MyLikeTravelogueResponse.java b/backend/src/main/java/kr/touroot/member/dto/response/MyLikeTravelogueResponse.java
new file mode 100644
index 000000000..a3840e0e9
--- /dev/null
+++ b/backend/src/main/java/kr/touroot/member/dto/response/MyLikeTravelogueResponse.java
@@ -0,0 +1,31 @@
+package kr.touroot.member.dto.response;
+
+import java.time.format.DateTimeFormatter;
+import kr.touroot.travelogue.domain.Travelogue;
+import lombok.Builder;
+
+@Builder
+public record MyLikeTravelogueResponse(
+        long id,
+        String title,
+        String thumbnailUrl,
+        String createdAt,
+        String authorName,
+        String authorProfileImageUrl
+) {
+
+    public static MyLikeTravelogueResponse from(Travelogue travelogue) {
+        String createdAt = travelogue.getCreatedAt()
+                .toLocalDate()
+                .format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
+
+        return MyLikeTravelogueResponse.builder()
+                .id(travelogue.getId())
+                .title(travelogue.getTitle())
+                .thumbnailUrl(travelogue.getThumbnail())
+                .createdAt(createdAt)
+                .authorName(travelogue.getAuthorNickname())
+                .authorProfileImageUrl(travelogue.getAuthorProfileImageUrl())
+                .build();
+    }
+}
diff --git a/backend/src/main/java/kr/touroot/member/service/MyPageFacadeService.java b/backend/src/main/java/kr/touroot/member/service/MyPageFacadeService.java
index f495395f3..5644377ca 100644
--- a/backend/src/main/java/kr/touroot/member/service/MyPageFacadeService.java
+++ b/backend/src/main/java/kr/touroot/member/service/MyPageFacadeService.java
@@ -3,9 +3,12 @@
 import kr.touroot.global.auth.dto.MemberAuth;
 import kr.touroot.member.domain.Member;
 import kr.touroot.member.dto.request.ProfileUpdateRequest;
+import kr.touroot.member.dto.response.MyLikeTravelogueResponse;
 import kr.touroot.member.dto.response.MyTravelogueResponse;
 import kr.touroot.member.dto.response.ProfileResponse;
 import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueLike;
+import kr.touroot.travelogue.service.TravelogueLikeService;
 import kr.touroot.travelogue.service.TravelogueService;
 import kr.touroot.travelplan.domain.TravelPlan;
 import kr.touroot.travelplan.dto.response.PlanResponse;
@@ -23,6 +26,7 @@ public class MyPageFacadeService {
     private final MemberService memberService;
     private final TravelogueService travelogueService;
     private final TravelPlanService travelPlanService;
+    private final TravelogueLikeService travelogueLikeService;
 
     @Transactional(readOnly = true)
     public ProfileResponse readProfile(MemberAuth memberAuth) {
@@ -46,6 +50,15 @@ public Page<PlanResponse> readTravelPlans(MemberAuth memberAuth, Pageable pageab
         return travelPlans.map(PlanResponse::from);
     }
 
+    @Transactional(readOnly = true)
+    public Page<MyLikeTravelogueResponse> readLikes(MemberAuth memberAuth, Pageable pageable) {
+        Member member = memberService.getMemberById(memberAuth.memberId());
+
+        return travelogueLikeService.findByLiker(member, pageable)
+                .map(TravelogueLike::getTravelogue)
+                .map(MyLikeTravelogueResponse::from);
+    }
+
     @Transactional
     public ProfileResponse updateProfile(ProfileUpdateRequest request, MemberAuth memberAuth) {
         return memberService.updateProfile(request, memberAuth);
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueLikeRepository.java b/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueLikeRepository.java
index 52df6652c..31aa2f1aa 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueLikeRepository.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/TravelogueLikeRepository.java
@@ -3,10 +3,14 @@
 import kr.touroot.member.domain.Member;
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueLike;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface TravelogueLikeRepository extends JpaRepository<TravelogueLike, Long> {
 
+    Page<TravelogueLike> findAllByLiker(Member liker, Pageable pageable);
+
     boolean existsByTravelogueAndLiker(Travelogue travelogue, Member liker);
 
     void deleteAllByTravelogue(Travelogue travelogue);
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueLikeService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueLikeService.java
index a5f6eea85..82b193c8b 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueLikeService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueLikeService.java
@@ -5,6 +5,8 @@
 import kr.touroot.travelogue.domain.TravelogueLike;
 import kr.touroot.travelogue.repository.TravelogueLikeRepository;
 import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -14,6 +16,11 @@ public class TravelogueLikeService {
 
     private final TravelogueLikeRepository travelogueLikeRepository;
 
+    @Transactional(readOnly = true)
+    public Page<TravelogueLike> findByLiker(Member liker, Pageable pageable) {
+        return travelogueLikeRepository.findAllByLiker(liker, pageable);
+    }
+
     @Transactional(readOnly = true)
     public boolean existByTravelogueAndMember(Travelogue travelogue, Member liker) {
         return travelogueLikeRepository.existsByTravelogueAndLiker(travelogue, liker);
diff --git a/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java b/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
index 93051ab46..3676ead71 100644
--- a/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
+++ b/backend/src/test/java/kr/touroot/member/controller/MyPageControllerTest.java
@@ -101,6 +101,25 @@ void readTravelPlans() {
                 .body("content.size()", is(2));
     }
 
+    @DisplayName("마이 페이지 컨트롤러는 내가 좋아요 한 여행기 조회 시 요청이 들어오면 로그인한 사용자의 여행 계획을 조회한다.")
+    @Test
+    void readLikeTravelogues() {
+        // given
+        travelogueTestHelper.initTravelogueTestDataWithLike(member);
+        travelogueTestHelper.initTravelogueTestDataWithLike(member);
+        travelogueTestHelper.initTravelogueTestData();
+
+        // when & then
+        RestAssured.given().log().all()
+                .contentType(ContentType.JSON)
+                .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
+                .when().log().all()
+                .get("/api/v1/member/me/likes")
+                .then().log().all()
+                .statusCode(200)
+                .body("content.size()", is(2));
+    }
+
     @DisplayName("마이 페이지 컨트롤러는 내 프로필 수정 요청이 들어오면 로그인한 사용자의 프로필을 수정한다.")
     @Test
     void updateProfile() {
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueLikeServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueLikeServiceTest.java
index f1dd162b0..509082643 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueLikeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueLikeServiceTest.java
@@ -12,12 +12,15 @@
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Import;
+import org.springframework.data.domain.Pageable;
 
 @DisplayName("여행기 좋아요 서비스")
 @Import(value = {TravelogueLikeService.class, TravelogueTestHelper.class})
 @ServiceTest
 class TravelogueLikeServiceTest {
 
+    public static final int BASIC_PAGE_SIZE = 5;
+
     private final TravelogueLikeService travelogueLikeService;
     private final DatabaseCleaner databaseCleaner;
     private final TravelogueTestHelper testHelper;
@@ -38,6 +41,20 @@ void setUp() {
         databaseCleaner.executeTruncate();
     }
 
+    @DisplayName("특정 멤버가 좋아요 한 여행기를 조회할 수 있다.")
+    @Test
+    void findByLiker() {
+        // given
+        Member liker = testHelper.initKakaoMemberTestData();
+        testHelper.initTravelogueTestDataWithLike(liker);
+        testHelper.initTravelogueTestDataWithLike(liker);
+        testHelper.initTravelogueTestData();
+
+        // when & then
+        assertThat(travelogueLikeService.findByLiker(liker, Pageable.ofSize(BASIC_PAGE_SIZE)))
+                .hasSize(2);
+    }
+
     @DisplayName("특정 여행기에 특정 멤버가 좋아요 했는지 알 수 있다")
     @Test
     void existByTravelogueAndMember() {

From 755c5c80b009ee405bd85ba4fa366fcd5b94ad34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Mon, 21 Oct 2024 13:16:12 +0900
Subject: [PATCH 07/13] =?UTF-8?q?[Fix]=20=ED=94=84=EB=A1=9C=ED=95=84=20?=
 =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EB=B9=88=20=EA=B0=92=20=EC=98=88=EC=99=B8?=
 =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=82=AD=EC=A0=9C=20(#542)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/kr/touroot/member/domain/Member.java |  8 +++++++-
 .../member/dto/request/ProfileUpdateRequest.java       |  3 ++-
 .../java/kr/touroot/member/service/MemberService.java  | 10 ++++++----
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/member/domain/Member.java b/backend/src/main/java/kr/touroot/member/domain/Member.java
index bef12987c..7de4c5de8 100644
--- a/backend/src/main/java/kr/touroot/member/domain/Member.java
+++ b/backend/src/main/java/kr/touroot/member/domain/Member.java
@@ -131,9 +131,15 @@ private void validateProfileImageUrlForm(String profileImageUrl) {
         }
     }
 
+    private void validateProfileImageUrlNotNull(String profileImageUrl) {
+        if (profileImageUrl == null) {
+            throw new BadRequestException("프로필 이미지는 비어 있을 수 없습니다");
+        }
+    }
+
     public void update(String nickname, String profileImageUrl) {
         validateNickname(nickname);
-        validateProfileImageUrl(profileImageUrl);
+        validateProfileImageUrlNotNull(profileImageUrl);
         this.nickname = nickname;
         this.profileImageUrl = profileImageUrl;
     }
diff --git a/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java b/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
index fc998bb06..280bd4d8b 100644
--- a/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
+++ b/backend/src/main/java/kr/touroot/member/dto/request/ProfileUpdateRequest.java
@@ -2,13 +2,14 @@
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 
 public record ProfileUpdateRequest(
         @Schema(description = "사용자 닉네임", example = "아기뚜리")
         @NotBlank(message = "닉네임은 비어있을 수 없습니다.")
         String nickname,
         @Schema(description = "사용자 프로필 사진 URL", example = "https://dev.touroot.kr/profile-image-ex.png")
-        @NotBlank(message = "프로필 사진 URL은 비어있을 수 없습니다.")
+        @NotNull(message = "프로필 사진 URL은 null 값일 수 없습니다.")
         String profileImageUrl
 ) {
 }
diff --git a/backend/src/main/java/kr/touroot/member/service/MemberService.java b/backend/src/main/java/kr/touroot/member/service/MemberService.java
index b3414dc20..b2e455308 100644
--- a/backend/src/main/java/kr/touroot/member/service/MemberService.java
+++ b/backend/src/main/java/kr/touroot/member/service/MemberService.java
@@ -58,14 +58,16 @@ private void validateNicknameDuplication(String nickname) {
     public ProfileResponse updateProfile(ProfileUpdateRequest request, MemberAuth memberAuth) {
         Member member = getMemberById(memberAuth.memberId());
         String requestProfileImageUrl = request.profileImageUrl();
-        if (!Objects.equals(request.profileImageUrl(), member.getProfileImageUrl())) {
+        if (isUpdatable(requestProfileImageUrl, member)) {
             requestProfileImageUrl = s3Provider.copyImageToPermanentStorage(request.profileImageUrl());
         }
         member.update(request.nickname(), requestProfileImageUrl);
 
-//        Member member = getMemberById(memberAuth.memberId());
-//        member.changeNickname(request.nickname());
-
         return ProfileResponse.from(member);
     }
+
+    private boolean isUpdatable(String requestProfileImageUrl, Member member) {
+        return !requestProfileImageUrl.isEmpty() && !Objects.equals(requestProfileImageUrl,
+                member.getProfileImageUrl());
+    }
 }

From bccfe51166a5bdacac005288b17f483d3bd6c1d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Mon, 21 Oct 2024 20:01:12 +0900
Subject: [PATCH 08/13] =?UTF-8?q?[Feature]=20-=20=EA=B2=80=EC=83=89=20?=
 =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EB=B6=84=EA=B8=B0=20=EA=B3=84=EC=B8=B5=20?=
 =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#555)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../travelogue/domain/search/CountryCode.java |  4 +--
 .../query/TravelogueQueryRepository.java      |  3 --
 .../query/TravelogueQueryRepositoryImpl.java  | 32 ++++++++++---------
 .../travelogue/service/TravelogueService.java |  9 ------
 .../domain/search/CountryCodeTest.java        | 11 +++----
 5 files changed, 24 insertions(+), 35 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
index 6ec439a9a..a20793d71 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
@@ -2,10 +2,10 @@
 
 import java.util.Arrays;
 import java.util.Set;
-import kr.touroot.global.exception.BadRequestException;
 
 public enum CountryCode {
 
+    NONE(Set.of()),
     AF(Set.of("아프가니스탄")),
     AL(Set.of("알바니아")),
     DZ(Set.of("알제리")),
@@ -256,6 +256,6 @@ public static CountryCode findByName(String name) {
         return Arrays.stream(values())
                 .filter(code -> code.names.contains(name))
                 .findFirst()
-                .orElseThrow(() -> new BadRequestException("국가 이름을 찾을 수 없습니다."));
+                .orElse(NONE);
     }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
index 853c9ca63..7d4eae28d 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
@@ -2,7 +2,6 @@
 
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
-import kr.touroot.travelogue.domain.search.CountryCode;
 import kr.touroot.travelogue.domain.search.SearchCondition;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
@@ -11,7 +10,5 @@ public interface TravelogueQueryRepository {
 
     Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pageable pageable);
 
-    Page<Travelogue> findByKeywordAndCountryCode(CountryCode countryCode, Pageable pageable);
-
     Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable);
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
index d47be6d55..2b22ab225 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
@@ -36,30 +36,32 @@ public class TravelogueQueryRepositoryImpl implements TravelogueQueryRepository
     @Override
     public Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pageable pageable) {
         String keyword = condition.getKeyword();
-        List<Travelogue> results = jpaQueryFactory.selectFrom(travelogue)
-                .where(Expressions.stringTemplate(TEMPLATE, getTargetField(condition.getSearchType()))
-                        .containsIgnoreCase(keyword.replace(BLANK, EMPTY)))
-                .orderBy(travelogue.id.desc())
-                .offset(pageable.getOffset())
+        JPAQuery<Travelogue> query = jpaQueryFactory.selectFrom(travelogue);
+        if (condition.getSearchType() == SearchType.COUNTRY) {
+            CountryCode countryCode = CountryCode.findByName(keyword);
+            findByCountryCode(query, countryCode);
+        }
+        if (condition.getSearchType() == SearchType.AUTHOR || condition.getSearchType() == SearchType.TITLE) {
+            findByTitleOrAuthor(condition, query, keyword);
+        }
+        List<Travelogue> results = query.offset(pageable.getOffset())
                 .limit(pageable.getPageSize())
                 .fetch();
 
         return new PageImpl<>(results, pageable, results.size());
     }
 
-    @Override
-    public Page<Travelogue> findByKeywordAndCountryCode(CountryCode countryCode, Pageable pageable) {
-        List<Travelogue> results = jpaQueryFactory.select(travelogue)
-                .from(travelogue)
-                .join(travelogueCountry)
+    private void findByCountryCode(JPAQuery<Travelogue> query, CountryCode countryCode) {
+        query.join(travelogueCountry)
                 .on(travelogue.id.eq(travelogueCountry.travelogue.id))
                 .where(travelogueCountry.countryCode.eq(countryCode))
-                .orderBy(travelogueCountry.count.desc())
-                .offset(pageable.getOffset())
-                .limit(pageable.getPageSize())
-                .fetch();
+                .orderBy(travelogueCountry.count.desc());
+    }
 
-        return new PageImpl<>(results, pageable, results.size());
+    private void findByTitleOrAuthor(SearchCondition condition, JPAQuery<Travelogue> query, String keyword) {
+        query.where(Expressions.stringTemplate(TEMPLATE, getTargetField(condition.getSearchType()))
+                        .containsIgnoreCase(keyword.replace(BLANK, EMPTY)))
+                .orderBy(travelogue.id.desc());
     }
 
     private StringPath getTargetField(SearchType searchType) {
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
index eb67a40be..4a42a7ef8 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
@@ -5,7 +5,6 @@
 import kr.touroot.member.domain.Member;
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
-import kr.touroot.travelogue.domain.search.CountryCode;
 import kr.touroot.travelogue.domain.search.SearchCondition;
 import kr.touroot.travelogue.domain.search.SearchType;
 import kr.touroot.travelogue.dto.request.TravelogueRequest;
@@ -44,19 +43,11 @@ public Page<Travelogue> findAllByMember(Member member, Pageable pageable) {
     @Transactional(readOnly = true)
     public Page<Travelogue> findByKeyword(TravelogueSearchRequest request, Pageable pageable) {
         SearchType searchType = SearchType.from(request.searchType());
-        if (searchType == SearchType.COUNTRY) {
-            return findByKeywordAndCountryCode(request.keyword(), pageable);
-        }
         SearchCondition searchCondition = new SearchCondition(request.keyword(), searchType);
 
         return travelogueQueryRepository.findByKeywordAndSearchType(searchCondition, pageable);
     }
 
-    private Page<Travelogue> findByKeywordAndCountryCode(String keyword, Pageable pageable) {
-        CountryCode countryCode = CountryCode.findByName(keyword);
-        return travelogueQueryRepository.findByKeywordAndCountryCode(countryCode, pageable);
-    }
-
     @Transactional(readOnly = true)
     public Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable) {
         if (filter.isEmptyCondition()) {
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
index 6a268d0a3..3f4825b4e 100644
--- a/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
@@ -1,9 +1,7 @@
 package kr.touroot.travelogue.domain.search;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import kr.touroot.global.exception.BadRequestException;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -21,11 +19,12 @@ void findByName(String name) {
                 .isEqualTo(CountryCode.KR);
     }
 
-    @DisplayName("없는 나라 이름으로 찾으면 예외로 처리한다.")
+    @DisplayName("없는 나라 이름으로 찾으면 NONE을 반환한다.")
     @Test
     void findByNonCountryName() {
-        assertThatThrownBy(() -> CountryCode.findByName("미역국"))
-                .isInstanceOf(BadRequestException.class)
-                .hasMessage("국가 이름을 찾을 수 없습니다.");
+        CountryCode code = CountryCode.findByName("미역국");
+
+        assertThat(code)
+                .isEqualTo(CountryCode.NONE);
     }
 }

From cee8fd5a2a3a7e4771f7fd880cbc48583446625c Mon Sep 17 00:00:00 2001
From: eunjungL <62099953+eunjungL@users.noreply.github.com>
Date: Tue, 22 Oct 2024 12:55:15 +0900
Subject: [PATCH 09/13] =?UTF-8?q?[Feature]=20-=20=EA=B2=80=EC=83=89=20+=20?=
 =?UTF-8?q?=ED=95=84=ED=84=B0=EB=A7=81=20API=20=ED=86=B5=ED=95=A9=20(#557)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat: 검색 및 필터링 API 통합

* refactor: 더 이상 사용하지 않는 filtering 관련 메서드 제거

* refactor: TravelogueQueryRepositoryImpl 메서드 순서 정리 및 TODO 추가

* refactor: TravelogueQueryRepositoryImpl 메서드 순서 정리 및 검색 API 삭제 TODO 추가

* test: 검색 테스트 필터와 검색 통합된 메서드로 변경
---
 .../controller/TravelogueController.java      | 13 +++-
 .../domain/search/SearchCondition.java        |  4 ++
 .../dto/request/TravelogueSearchRequest.java  | 17 ++++-
 .../query/TravelogueQueryRepository.java      |  4 +-
 .../query/TravelogueQueryRepositoryImpl.java  | 63 +++++++++++++------
 .../service/TravelogueFacadeService.java      |  6 +-
 .../travelogue/service/TravelogueService.java | 13 ++--
 .../controller/TravelogueControllerTest.java  |  8 ++-
 .../service/TravelogueFacadeServiceTest.java  | 39 ++++++++++--
 .../service/TravelogueServiceTest.java        | 34 +++++++---
 10 files changed, 155 insertions(+), 46 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/travelogue/controller/TravelogueController.java b/backend/src/main/java/kr/touroot/travelogue/controller/TravelogueController.java
index f9ed4e6d6..9a43c0cc2 100644
--- a/backend/src/main/java/kr/touroot/travelogue/controller/TravelogueController.java
+++ b/backend/src/main/java/kr/touroot/travelogue/controller/TravelogueController.java
@@ -141,11 +141,20 @@ public ResponseEntity<Page<TravelogueSimpleResponse>> findMainPageTravelogues(
             @Parameter(hidden = true)
             @PageableDefault(size = 5, sort = "id", direction = Direction.DESC)
             Pageable pageable,
-            TravelogueFilterRequest filter
+            TravelogueFilterRequest filterRequest,
+            @Valid
+            TravelogueSearchRequest searchRequest
+
     ) {
-        return ResponseEntity.ok(travelogueFacadeService.findSimpleTravelogues(filter, pageable));
+        Page<TravelogueSimpleResponse> data = travelogueFacadeService.findSimpleTravelogues(
+                filterRequest,
+                searchRequest,
+                pageable
+        );
+        return ResponseEntity.ok(data);
     }
 
+    // TODO: 프론트엔드 엔드포인트 이전 작업 완료 후 제거
     @Operation(summary = "여행기 검색")
     @ApiResponses(value = {
             @ApiResponse(
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
index e8fe8fd4e..af30d3794 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
@@ -12,4 +12,8 @@ public SearchCondition(String keyword, SearchType searchType) {
         this.keyword = keyword;
         this.searchType = searchType;
     }
+
+    public boolean isEmptyCondition() {
+        return keyword == null && searchType == null;
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java b/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
index c03c6003e..f851258e5 100644
--- a/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
+++ b/backend/src/main/java/kr/touroot/travelogue/dto/request/TravelogueSearchRequest.java
@@ -1,16 +1,27 @@
 package kr.touroot.travelogue.dto.request;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.Size;
+import kr.touroot.travelogue.domain.search.SearchCondition;
+import kr.touroot.travelogue.domain.search.SearchType;
 
 public record TravelogueSearchRequest(
         @Schema(description = "검색어 (제목, 작성자 닉네임 모두 가능)", example = "서울")
-        @NotBlank(message = "검색어는 2글자 이상이어야 합니다.")
         @Size(min = 2, message = "검색어는 2글자 이상이어야 합니다.")
         String keyword,
         @Schema(description = "검색 키워드 종류 (TITLE, AUTHOR, COUNTRY)", example = "TITLE")
-        @NotBlank(message = "검색 키워드 종류는 필수입니다.")
         String searchType
 ) {
+
+    public SearchCondition toSearchCondition() {
+        return new SearchCondition(keyword, getSearchType());
+    }
+
+    private SearchType getSearchType() {
+        if (this.searchType == null) {
+            return null;
+        }
+
+        return SearchType.from(this.searchType);
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
index 7d4eae28d..91f6cb164 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepository.java
@@ -8,7 +8,7 @@
 
 public interface TravelogueQueryRepository {
 
-    Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pageable pageable);
+    Page<Travelogue> findAllBySearchCondition(SearchCondition condition, Pageable pageable);
 
-    Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable);
+    Page<Travelogue> findAllByCondition(SearchCondition searchCondition, TravelogueFilterCondition filterCondition, Pageable pageable);
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
index 2b22ab225..2094b66fb 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
@@ -34,21 +34,36 @@ public class TravelogueQueryRepositoryImpl implements TravelogueQueryRepository
     private final JPAQueryFactory jpaQueryFactory;
 
     @Override
-    public Page<Travelogue> findByKeywordAndSearchType(SearchCondition condition, Pageable pageable) {
+    public Page<Travelogue> findAllByCondition(
+            SearchCondition searchCondition,
+            TravelogueFilterCondition filterCondition,
+            Pageable pageable
+    ) {
+        JPAQuery<Travelogue> baseQuery = jpaQueryFactory.selectFrom(travelogue);
+
+        addSearchCondition(baseQuery, searchCondition);
+        addFilterCondition(baseQuery, filterCondition);
+
+        List<Travelogue> results = baseQuery.orderBy(findSortCondition(pageable.getSort()))
+                .offset(pageable.getOffset())
+                .limit(pageable.getPageSize())
+                .fetch();
+
+        return new PageImpl<>(results, pageable, results.size());
+    }
+
+    private void addSearchCondition(JPAQuery<Travelogue> query, SearchCondition condition) {
         String keyword = condition.getKeyword();
-        JPAQuery<Travelogue> query = jpaQueryFactory.selectFrom(travelogue);
+
         if (condition.getSearchType() == SearchType.COUNTRY) {
             CountryCode countryCode = CountryCode.findByName(keyword);
             findByCountryCode(query, countryCode);
+            return;
         }
+
         if (condition.getSearchType() == SearchType.AUTHOR || condition.getSearchType() == SearchType.TITLE) {
             findByTitleOrAuthor(condition, query, keyword);
         }
-        List<Travelogue> results = query.offset(pageable.getOffset())
-                .limit(pageable.getPageSize())
-                .fetch();
-
-        return new PageImpl<>(results, pageable, results.size());
     }
 
     private void findByCountryCode(JPAQuery<Travelogue> query, CountryCode countryCode) {
@@ -71,19 +86,9 @@ private StringPath getTargetField(SearchType searchType) {
         return travelogue.title;
     }
 
-    @Override
-    public Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable) {
-        JPAQuery<Travelogue> query = jpaQueryFactory.selectFrom(travelogue);
-
+    private void addFilterCondition(JPAQuery<Travelogue> query, TravelogueFilterCondition filter) {
         addTagFilter(query, filter);
         addPeriodFilter(query, filter);
-
-        List<Travelogue> results = query.orderBy(findSortCondition(pageable.getSort()))
-                .offset(pageable.getOffset())
-                .limit(pageable.getPageSize())
-                .fetch();
-
-        return new PageImpl<>(results, pageable, results.size());
     }
 
     public void addTagFilter(JPAQuery<Travelogue> query, TravelogueFilterCondition filter) {
@@ -132,4 +137,26 @@ private Order getDirection(Sort.Order order) {
 
         return Order.DESC;
     }
+
+    // TODO: 프론트엔드 엔드포인트 이전 작업 완료 후 제거
+    @Override
+    public Page<Travelogue> findAllBySearchCondition(SearchCondition condition, Pageable pageable) {
+        String keyword = condition.getKeyword();
+        JPAQuery<Travelogue> query = jpaQueryFactory.selectFrom(travelogue);
+
+        if (condition.getSearchType() == SearchType.COUNTRY) {
+            CountryCode countryCode = CountryCode.findByName(keyword);
+            findByCountryCode(query, countryCode);
+        }
+
+        if (condition.getSearchType() == SearchType.AUTHOR || condition.getSearchType() == SearchType.TITLE) {
+            findByTitleOrAuthor(condition, query, keyword);
+        }
+
+        List<Travelogue> results = query.offset(pageable.getOffset())
+                .limit(pageable.getPageSize())
+                .fetch();
+
+        return new PageImpl<>(results, pageable, results.size());
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
index 47ab457c5..c87274790 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
@@ -7,6 +7,7 @@
 import kr.touroot.travelogue.domain.Travelogue;
 import kr.touroot.travelogue.domain.TravelogueFilterCondition;
 import kr.touroot.travelogue.domain.TravelogueTag;
+import kr.touroot.travelogue.domain.search.SearchCondition;
 import kr.touroot.travelogue.dto.request.TravelogueFilterRequest;
 import kr.touroot.travelogue.dto.request.TravelogueRequest;
 import kr.touroot.travelogue.dto.request.TravelogueSearchRequest;
@@ -63,14 +64,17 @@ public TravelogueResponse findTravelogueByIdForAuthenticated(Long id, MemberAuth
     @Transactional(readOnly = true)
     public Page<TravelogueSimpleResponse> findSimpleTravelogues(
             TravelogueFilterRequest filterRequest,
+            TravelogueSearchRequest searchRequest,
             Pageable pageable
     ) {
         TravelogueFilterCondition filter = filterRequest.toFilterCondition();
-        Page<Travelogue> travelogues = travelogueService.findAllByFilter(filter, pageable);
+        SearchCondition searchCondition = searchRequest.toSearchCondition();
+        Page<Travelogue> travelogues = travelogueService.findAll(searchCondition, filter, pageable);
 
         return travelogues.map(this::getTravelogueSimpleResponse);
     }
 
+    // TODO: 프론트엔드 엔드포인트 이전 작업 완료 후 제거
     @Transactional(readOnly = true)
     public Page<TravelogueSimpleResponse> findSimpleTravelogues(TravelogueSearchRequest request, Pageable pageable) {
         Page<Travelogue> travelogues = travelogueService.findByKeyword(request, pageable);
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
index 4a42a7ef8..48cf73f31 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
@@ -40,21 +40,26 @@ public Page<Travelogue> findAllByMember(Member member, Pageable pageable) {
         return travelogueRepository.findAllByAuthor(member, pageable);
     }
 
+    // TODO: 프론트엔드 엔드포인트 이전 작업 완료 후 제거
     @Transactional(readOnly = true)
     public Page<Travelogue> findByKeyword(TravelogueSearchRequest request, Pageable pageable) {
         SearchType searchType = SearchType.from(request.searchType());
         SearchCondition searchCondition = new SearchCondition(request.keyword(), searchType);
 
-        return travelogueQueryRepository.findByKeywordAndSearchType(searchCondition, pageable);
+        return travelogueQueryRepository.findAllBySearchCondition(searchCondition, pageable);
     }
 
     @Transactional(readOnly = true)
-    public Page<Travelogue> findAllByFilter(TravelogueFilterCondition filter, Pageable pageable) {
-        if (filter.isEmptyCondition()) {
+    public Page<Travelogue> findAll(
+            SearchCondition searchCondition,
+            TravelogueFilterCondition filter,
+            Pageable pageable
+    ) {
+        if (filter.isEmptyCondition() && searchCondition.isEmptyCondition()) {
             return travelogueRepository.findAll(pageable);
         }
 
-        return travelogueQueryRepository.findAllByFilter(filter, pageable);
+        return travelogueQueryRepository.findAllByCondition(searchCondition, filter, pageable);
     }
 
     @Transactional
diff --git a/backend/src/test/java/kr/touroot/travelogue/controller/TravelogueControllerTest.java b/backend/src/test/java/kr/touroot/travelogue/controller/TravelogueControllerTest.java
index d2ef43315..d2b649109 100644
--- a/backend/src/test/java/kr/touroot/travelogue/controller/TravelogueControllerTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/controller/TravelogueControllerTest.java
@@ -28,6 +28,7 @@
 import kr.touroot.travelogue.helper.TravelogueTestHelper;
 import kr.touroot.utils.DatabaseCleaner;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -389,7 +390,7 @@ void findTraveloguesByTitleKeyword() throws JsonProcessingException {
                 .param("searchType", "TITLE")
                 .log().all()
                 .accept(ContentType.JSON)
-                .when().get("/api/v1/travelogues/search")
+                .when().get("/api/v1/travelogues")
                 .then().log().all()
                 .statusCode(200).assertThat()
                 .body(is(objectMapper.writeValueAsString(responses)));
@@ -407,7 +408,7 @@ void findTraveloguesKeywordNotBlank(String keyword) {
                 .param("searchType", "TITLE")
                 .log().all()
                 .accept(ContentType.JSON)
-                .when().get("/api/v1/travelogues/search")
+                .when().get("/api/v1/travelogues")
                 .then().log().all()
                 .statusCode(400).assertThat()
                 .body("message", is("검색어는 2글자 이상이어야 합니다."));
@@ -425,12 +426,13 @@ void findTraveloguesKeywordWithMiddleBlank(String keyword) throws JsonProcessing
                 .param("searchType", "TITLE")
                 .log().all()
                 .accept(ContentType.JSON)
-                .when().get("/api/v1/travelogues/search")
+                .when().get("/api/v1/travelogues")
                 .then().log().all()
                 .statusCode(200).assertThat()
                 .body(is(objectMapper.writeValueAsString(responses)));
     }
 
+    @Disabled // 검색과 필터링 API 통합으로 검색 키워드 빈 값 가능
     @DisplayName("검색 키워드의 종류를 명시해야 한다.")
     @Test
     void findTraveloguesByKeywordWithoutSearchType() {
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
index 99ae5bb92..ffb2c195d 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
@@ -147,12 +147,17 @@ void findTravelogueByIdAndLiker() {
     @DisplayName("메인 페이지에 표시할 여행기 목록을 조회한다.")
     @Test
     void findTravelogues() {
+        TravelogueSearchRequest searchRequest = new TravelogueSearchRequest(null, null);
         TravelogueFilterRequest filterRequest = new TravelogueFilterRequest(null, null);
         testHelper.initAllTravelogueTestData();
         Page<TravelogueSimpleResponse> expect = TravelogueResponseFixture.getTravelogueSimpleResponses();
 
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
-        Page<TravelogueSimpleResponse> result = service.findSimpleTravelogues(filterRequest, pageRequest);
+        Page<TravelogueSimpleResponse> result = service.findSimpleTravelogues(
+                filterRequest,
+                searchRequest,
+                pageRequest
+        );
 
         assertThat(result).containsAll(expect);
     }
@@ -164,9 +169,10 @@ void filterTravelogues() {
         testHelper.initAllTravelogueTestData();
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
         TravelogueFilterRequest filter = new TravelogueFilterRequest(List.of(1L), null);
+        TravelogueSearchRequest searchRequest = new TravelogueSearchRequest(null, null);
 
         // when
-        Page<TravelogueSimpleResponse> result = service.findSimpleTravelogues(filter, pageRequest);
+        Page<TravelogueSimpleResponse> result = service.findSimpleTravelogues(filter, searchRequest, pageRequest);
 
         // then
         assertThat(result.getContent()).hasSize(1);
@@ -175,39 +181,62 @@ void filterTravelogues() {
     @DisplayName("제목 키워드를 기반으로 여행기 목록을 조회한다.")
     @Test
     void findTraveloguesByTitleKeyword() {
+        // given
         testHelper.initAllTravelogueTestData();
         Page<TravelogueSimpleResponse> responses = TravelogueResponseFixture.getTravelogueSimpleResponses();
 
         TravelogueSearchRequest searchRequest = new TravelogueSearchRequest("제주", "title");
+        TravelogueFilterRequest filterRequest = new TravelogueFilterRequest(null, null);
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
-        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(searchRequest, pageRequest);
 
+        // when
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(
+                filterRequest,
+                searchRequest,
+                pageRequest
+        );
+
+        // then
         assertThat(searchResults).containsAll(responses);
     }
 
     @DisplayName("사용자 닉네임을 기반으로 여행기 목록을 조회한다.")
     @Test
     void findTraveloguesByAuthorNicknameKeyword() {
+        // given
         testHelper.initAllTravelogueTestData();
         Page<TravelogueSimpleResponse> responses = TravelogueResponseFixture.getTravelogueSimpleResponses();
 
         TravelogueSearchRequest searchRequest = new TravelogueSearchRequest("리비", "author");
+        TravelogueFilterRequest filterRequest = new TravelogueFilterRequest(null, null);
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
-        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(searchRequest, pageRequest);
 
+        // when
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(
+                filterRequest,
+                searchRequest,
+                pageRequest
+        );
+
+        // then
         assertThat(searchResults).containsAll(responses);
     }
 
     @DisplayName("국가 코드를 기반으로 여행기 목록을 조회한다.")
     @Test
     void findTraveloguesByCountryCodeKeyword() {
+        // given
         testHelper.initAllTravelogueTestData();
         Page<TravelogueSimpleResponse> responses = TravelogueResponseFixture.getTravelogueSimpleResponses();
 
         TravelogueSearchRequest searchRequest = new TravelogueSearchRequest("한국", "country");
+        TravelogueFilterRequest filterRequest = new TravelogueFilterRequest(null, null);
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
-        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(searchRequest, pageRequest);
 
+        // when
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(filterRequest, searchRequest, pageRequest);
+
+        // then
         assertThat(searchResults).containsAll(responses);
     }
 
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
index 8d0b91b0c..20409b85c 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
@@ -12,11 +12,13 @@
 import kr.touroot.global.exception.ForbiddenException;
 import kr.touroot.member.domain.Member;
 import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueFilterCondition;
+import kr.touroot.travelogue.domain.search.SearchCondition;
+import kr.touroot.travelogue.domain.search.SearchType;
 import kr.touroot.travelogue.dto.request.TravelogueDayRequest;
 import kr.touroot.travelogue.dto.request.TraveloguePhotoRequest;
 import kr.touroot.travelogue.dto.request.TraveloguePlaceRequest;
 import kr.touroot.travelogue.dto.request.TravelogueRequest;
-import kr.touroot.travelogue.dto.request.TravelogueSearchRequest;
 import kr.touroot.travelogue.fixture.TravelogueFixture;
 import kr.touroot.travelogue.fixture.TravelogueRequestFixture;
 import kr.touroot.travelogue.helper.TravelogueTestHelper;
@@ -26,7 +28,9 @@
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Import;
-import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
 
 @DisplayName("여행기 서비스")
 @Import(value = {TravelogueService.class, TravelogueTestHelper.class, TestQueryDslConfig.class})
@@ -90,21 +94,35 @@ void getTravelogueByNotExistsIdThrowException() {
     @DisplayName("여행기를 검색할 수 있다.")
     @Test
     void findByKeyword() {
+        // given
         testHelper.initTravelogueTestData();
-        TravelogueSearchRequest request = new TravelogueSearchRequest("제주", "title");
 
-        assertThat(travelogueService.findByKeyword(request, Pageable.ofSize(BASIC_PAGE_SIZE)))
-                .hasSize(1);
+        SearchCondition searchCondition = new SearchCondition("제주", SearchType.TITLE);
+        TravelogueFilterCondition filter = new TravelogueFilterCondition(null, null);
+        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("createdAt"));
+
+        // when
+        Page<Travelogue> actual = travelogueService.findAll(searchCondition, filter, pageRequest);
+
+        // then
+        assertThat(actual).hasSize(1);
     }
 
     @DisplayName("존재하지 않는 키워드로 여행기를 조회하면 빈 페이지가 반환된다.")
     @Test
     void findByKeywordWithNotExistRequest() {
+        // given
         testHelper.initTravelogueTestData();
-        TravelogueSearchRequest request = new TravelogueSearchRequest("서울", "title");
 
-        assertThat(travelogueService.findByKeyword(request, Pageable.ofSize(BASIC_PAGE_SIZE)))
-                .isEmpty();
+        SearchCondition searchCondition = new SearchCondition("서울", SearchType.TITLE);
+        TravelogueFilterCondition filter = new TravelogueFilterCondition(null, null);
+        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("createdAt"));
+
+        // when
+        Page<Travelogue> actual = travelogueService.findAll(searchCondition, filter, pageRequest);
+
+        // then
+        assertThat(actual).isEmpty();
     }
 
     @DisplayName("여행기를 수정할 수 있다.")

From f736f2fbd26b761603da8167dff8308047868481 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Wed, 23 Oct 2024 10:34:33 +0900
Subject: [PATCH 10/13] =?UTF-8?q?[Feature]=20-=20=EC=97=AC=ED=96=89?=
 =?UTF-8?q?=EA=B8=B0,=20=EC=97=AC=ED=96=89=20=EA=B3=84=ED=9A=8D=20?=
 =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20=EA=B5=AD=EA=B0=80=20?=
 =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80=20?=
 =?UTF-8?q?(#568)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../travelogue/domain/TraveloguePlace.java    | 39 ++++++++++---
 .../travelogue/domain/search/CountryCode.java |  4 ++
 .../dto/request/TraveloguePlaceRequest.java   |  5 +-
 .../dto/response/TraveloguePlaceResponse.java |  5 +-
 .../travelplan/domain/TravelPlanPlace.java    | 38 ++++++++++---
 .../dto/request/PlanPlaceRequest.java         |  8 ++-
 .../dto/response/PlanPlaceResponse.java       |  4 +-
 ...y.sql => V6.0__add_travelogue_country.sql} |  0
 .../mysql/V6.1__add_country_code_column.sql   |  5 ++
 .../mysql/V6.2__update_country_code_none.sql  |  5 ++
 ...add_not_null_contraint_to_country_code.sql |  5 ++
 .../domain/TraveloguePlaceTest.java           | 56 +++++++++++++++----
 .../fixture/TraveloguePlaceFixture.java       |  7 ++-
 .../fixture/TravelogueResponseFixture.java    |  1 +
 .../controller/TravelPlanControllerTest.java  |  5 ++
 .../domain/TravelPlanPlaceTest.java           | 46 +++++++++++----
 .../fixture/TravelPlanPlaceFixture.java       |  9 ++-
 .../helper/TravelPlanTestHelper.java          |  9 +--
 .../service/TravelPlanFacadeServiceTest.java  |  2 +
 .../service/TravelPlanServiceTest.java        |  1 +
 20 files changed, 198 insertions(+), 56 deletions(-)
 rename backend/src/main/resources/db/migration/mysql/{V6__add_travelogue_country.sql => V6.0__add_travelogue_country.sql} (100%)
 create mode 100644 backend/src/main/resources/db/migration/mysql/V6.1__add_country_code_column.sql
 create mode 100644 backend/src/main/resources/db/migration/mysql/V6.2__update_country_code_none.sql
 create mode 100644 backend/src/main/resources/db/migration/mysql/V6.3__add_not_null_contraint_to_country_code.sql

diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java b/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
index 99e29c526..680a87913 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
@@ -4,6 +4,8 @@
 import jakarta.persistence.Column;
 import jakarta.persistence.Embedded;
 import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
 import jakarta.persistence.FetchType;
 import jakarta.persistence.GeneratedValue;
 import jakarta.persistence.GenerationType;
@@ -17,6 +19,7 @@
 import kr.touroot.global.exception.BadRequestException;
 import kr.touroot.place.domain.Place;
 import kr.touroot.position.domain.Position;
+import kr.touroot.travelogue.domain.search.CountryCode;
 import lombok.AccessLevel;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
@@ -61,21 +64,27 @@ public class TraveloguePlace extends BaseEntity {
     @OneToMany(mappedBy = "traveloguePlace", cascade = CascadeType.ALL, orphanRemoval = true)
     private List<TraveloguePhoto> traveloguePhotos = new ArrayList<>();
 
+    @Column(nullable = false)
+    @Enumerated(EnumType.STRING)
+    private CountryCode countryCode;
+
     public TraveloguePlace(
             Long id,
             Integer order,
             String description,
             String name,
             Position position,
-            TravelogueDay travelogueDay
+            TravelogueDay travelogueDay,
+            String countryCode
     ) {
-        validate(order, description, name, position, travelogueDay);
+        validate(order, description, name, position, travelogueDay, countryCode);
         this.id = id;
         this.order = order;
         this.description = description;
         this.name = name;
         this.position = position;
         this.travelogueDay = travelogueDay;
+        this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
     }
 
     public TraveloguePlace(
@@ -84,9 +93,10 @@ public TraveloguePlace(
             String name,
             String latitude,
             String longitude,
-            TravelogueDay travelogueDay
+            TravelogueDay travelogueDay,
+            String countryCode
     ) {
-        this(null, order, description, name, new Position(latitude, longitude), travelogueDay);
+        this(null, order, description, name, new Position(latitude, longitude), travelogueDay, countryCode);
     }
 
     private void validate(
@@ -94,18 +104,21 @@ private void validate(
             String description,
             String name,
             Position coordinate,
-            TravelogueDay travelogueDay
+            TravelogueDay travelogueDay,
+            String countryCode
     ) {
-        validateNotNull(order, name, coordinate, travelogueDay);
+        validateNotNull(order, name, coordinate, travelogueDay, countryCode);
         validateNotBlank(name);
         validateOrderRange(order);
         validateDescriptionLength(description);
         validatePlaceNameLength(name);
+        validateCountryCode(countryCode);
     }
 
-    private void validateNotNull(Integer order, String name, Position coordinate, TravelogueDay day) {
-        if (order == null || name == null || coordinate == null || day == null) {
-            throw new BadRequestException("여행기 장소에서 순서와 장소 위치, 그리고 방문 날짜는 비어 있을 수 없습니다");
+    private void validateNotNull(Integer order, String name, Position coordinate, TravelogueDay day,
+                                 String countryCode) {
+        if (order == null || name == null || coordinate == null || day == null || countryCode == null) {
+            throw new BadRequestException("여행기 장소에서 순서와 장소 위치, 방문 날짜, 그리고 국가 코드는 비어 있을 수 없습니다");
         }
     }
 
@@ -133,6 +146,14 @@ private void validatePlaceNameLength(String placeName) {
         }
     }
 
+    private void validateCountryCode(String countryCode) {
+        try {
+            CountryCode.valueOfIgnoreCase(countryCode);
+        } catch (IllegalArgumentException e) {
+            throw new BadRequestException("존재하지 않는 국가 코드입니다");
+        }
+    }
+
     public void addPhoto(TraveloguePhoto photo) {
         traveloguePhotos.add(photo);
         photo.updateTraveloguePlace(this);
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
index a20793d71..eaf797e9f 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
@@ -258,4 +258,8 @@ public static CountryCode findByName(String name) {
                 .findFirst()
                 .orElse(NONE);
     }
+
+    public static CountryCode valueOfIgnoreCase(String name) {
+        return CountryCode.valueOf(name.toUpperCase());
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java b/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
index 8bd4c8988..3fa113a63 100644
--- a/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
+++ b/backend/src/main/java/kr/touroot/travelogue/dto/request/TraveloguePlaceRequest.java
@@ -27,7 +27,7 @@ public record TraveloguePlaceRequest(
         @Size(message = "여행기 장소 사진은 최대 10개입니다.", max = 10)
         @Valid
         List<TraveloguePhotoRequest> photoUrls,
-        @Schema(description = "여행기 장소 국가 코드")
+        @Schema(description = "여행기 장소 국가 코드", example = "KR")
         @NotBlank(message = "여행기 장소 국가 코드는 비어있을 수 없습니다.")
         String countryCode
 ) {
@@ -39,7 +39,8 @@ public TraveloguePlace toTraveloguePlace(int order, TravelogueDay travelogueDay)
                 placeName,
                 position().lat(),
                 position().lng(),
-                travelogueDay
+                travelogueDay,
+                countryCode
         );
         addTraveloguePhotos(traveloguePlace);
         return traveloguePlace;
diff --git a/backend/src/main/java/kr/touroot/travelogue/dto/response/TraveloguePlaceResponse.java b/backend/src/main/java/kr/touroot/travelogue/dto/response/TraveloguePlaceResponse.java
index c0e73ab34..55593dc95 100644
--- a/backend/src/main/java/kr/touroot/travelogue/dto/response/TraveloguePlaceResponse.java
+++ b/backend/src/main/java/kr/touroot/travelogue/dto/response/TraveloguePlaceResponse.java
@@ -15,7 +15,9 @@ public record TraveloguePlaceResponse(
         @Schema(description = "여행기 장소 설명", example = "성담 빌딩에 위치한 선릉 캠퍼스입니다.")
         String description,
         TraveloguePositionResponse position,
-        List<String> photoUrls
+        List<String> photoUrls,
+        @Schema(description = "여행기 장소 국가 코드", example = "KR")
+        String countryCode
 ) {
 
     public static TraveloguePlaceResponse from(TraveloguePlace traveloguePlace) {
@@ -25,6 +27,7 @@ public static TraveloguePlaceResponse from(TraveloguePlace traveloguePlace) {
                 .description(traveloguePlace.getDescription())
                 .position(TraveloguePositionResponse.from(traveloguePlace.getPosition()))
                 .photoUrls(getTraveloguePhotosResponse(traveloguePlace))
+                .countryCode(traveloguePlace.getCountryCode().name())
                 .build();
     }
 
diff --git a/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java b/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
index 256019a5a..11af2c9fe 100644
--- a/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
+++ b/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
@@ -4,6 +4,8 @@
 import jakarta.persistence.Column;
 import jakarta.persistence.Embedded;
 import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
 import jakarta.persistence.FetchType;
 import jakarta.persistence.GeneratedValue;
 import jakarta.persistence.GenerationType;
@@ -17,6 +19,7 @@
 import kr.touroot.global.exception.BadRequestException;
 import kr.touroot.place.domain.Place;
 import kr.touroot.position.domain.Position;
+import kr.touroot.travelogue.domain.search.CountryCode;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
@@ -56,30 +59,39 @@ public class TravelPlanPlace extends BaseEntity {
     @OneToMany(mappedBy = "travelPlanPlace", cascade = CascadeType.ALL, orphanRemoval = true)
     private List<TravelPlaceTodo> travelPlaceTodos = new ArrayList<>();
 
-    public TravelPlanPlace(Long id, Integer order, TravelPlanDay day, String name, Position position) {
-        validate(order, day, name, position);
+    @Column
+    @Enumerated(EnumType.STRING)
+    private CountryCode countryCode;
+
+    public TravelPlanPlace(Long id, Integer order, TravelPlanDay day, String name, Position position,
+                           String countryCode) {
+        validate(order, day, name, position, countryCode);
         this.id = id;
         this.order = order;
         this.day = day;
         this.name = name;
         this.position = position;
+        this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
     }
 
-    public TravelPlanPlace(Integer order, TravelPlanDay day, String name, String latitude, String longitude) {
-        this(null, order, day, name, new Position(latitude, longitude));
+    public TravelPlanPlace(Integer order, TravelPlanDay day, String name, String latitude, String longitude,
+                           String countryCode) {
+        this(null, order, day, name, new Position(latitude, longitude), countryCode);
     }
 
 
-    private void validate(Integer order, TravelPlanDay day, String name, Position coordinate) {
-        validateNotNull(order, day, name, coordinate);
+    private void validate(Integer order, TravelPlanDay day, String name, Position coordinate, String countryCode) {
+        validateNotNull(order, day, name, coordinate, countryCode);
         validateNotBlank(name);
         validateOrderRange(order);
         validatePlaceNameLength(name);
+        validateCountryCode(countryCode);
     }
 
-    private void validateNotNull(Integer order, TravelPlanDay day, String name, Position coordinate) {
-        if (order == null || day == null || name == null || coordinate == null) {
-            throw new BadRequestException("여행 계획 장소에서 순서와 날짜, 그리고 장소 위치는 비어 있을 수 없습니다");
+    private void validateNotNull(Integer order, TravelPlanDay day, String name, Position coordinate,
+                                 String countryCode) {
+        if (order == null || day == null || name == null || coordinate == null || countryCode == null) {
+            throw new BadRequestException("여행 계획 장소에서 순서와 날짜, 장소 위치, 그리고 국가 코드는 비어 있을 수 없습니다");
         }
     }
 
@@ -101,6 +113,14 @@ private void validatePlaceNameLength(String placeName) {
         }
     }
 
+    private void validateCountryCode(String countryCode) {
+        try {
+            CountryCode.valueOfIgnoreCase(countryCode);
+        } catch (IllegalArgumentException e) {
+            throw new BadRequestException("존재하지 않는 국가 코드입니다");
+        }
+    }
+
     public void addTodo(TravelPlaceTodo todo) {
         travelPlaceTodos.add(todo);
         todo.updateTravelPlanPlace(this);
diff --git a/backend/src/main/java/kr/touroot/travelplan/dto/request/PlanPlaceRequest.java b/backend/src/main/java/kr/touroot/travelplan/dto/request/PlanPlaceRequest.java
index 97f5645da..3217885f5 100644
--- a/backend/src/main/java/kr/touroot/travelplan/dto/request/PlanPlaceRequest.java
+++ b/backend/src/main/java/kr/touroot/travelplan/dto/request/PlanPlaceRequest.java
@@ -19,7 +19,10 @@ public record PlanPlaceRequest(
         PlanPositionRequest position,
         @Valid
         @NotNull(message = "TODO 리스트는 필수 입니다.")
-        List<PlanPlaceTodoRequest> todos
+        List<PlanPlaceTodoRequest> todos,
+        @Schema(description = "여행기 장소 국가 코드", example = "KR")
+        @NotBlank(message = "여행기 장소 국가 코드는 비어있을 수 없습니다.")
+        String countryCode
 ) {
 
     public TravelPlanPlace toPlanPlace(int order, TravelPlanDay day) {
@@ -28,7 +31,8 @@ public TravelPlanPlace toPlanPlace(int order, TravelPlanDay day) {
                 day,
                 placeName,
                 position().lat(),
-                position().lng()
+                position().lng(),
+                countryCode
         );
         addTodos(travelPlanPlace);
         return travelPlanPlace;
diff --git a/backend/src/main/java/kr/touroot/travelplan/dto/response/PlanPlaceResponse.java b/backend/src/main/java/kr/touroot/travelplan/dto/response/PlanPlaceResponse.java
index 235a9e0cc..1d8ea2bc6 100644
--- a/backend/src/main/java/kr/touroot/travelplan/dto/response/PlanPlaceResponse.java
+++ b/backend/src/main/java/kr/touroot/travelplan/dto/response/PlanPlaceResponse.java
@@ -10,7 +10,8 @@ public record PlanPlaceResponse(
         @Schema(description = "여행 장소 Id", example = "1") Long id,
         @Schema(description = "여행 장소 이름", example = "잠실한강공원") String placeName,
         @Schema(description = "여행 장소 위치") PlanPositionResponse position,
-        @Schema(description = "여행 장소 TODO") List<PlanPlaceTodoResponse> todos
+        @Schema(description = "여행 장소 TODO") List<PlanPlaceTodoResponse> todos,
+        @Schema(description = "국가 코드") String countryCode
 ) {
 
     public static PlanPlaceResponse from(TravelPlanPlace planPlace) {
@@ -19,6 +20,7 @@ public static PlanPlaceResponse from(TravelPlanPlace planPlace) {
                 .placeName(planPlace.getName())
                 .position(PlanPositionResponse.from(planPlace.getPosition()))
                 .todos(getTodoResponse(planPlace))
+                .countryCode(planPlace.getCountryCode().name())
                 .build();
     }
 
diff --git a/backend/src/main/resources/db/migration/mysql/V6__add_travelogue_country.sql b/backend/src/main/resources/db/migration/mysql/V6.0__add_travelogue_country.sql
similarity index 100%
rename from backend/src/main/resources/db/migration/mysql/V6__add_travelogue_country.sql
rename to backend/src/main/resources/db/migration/mysql/V6.0__add_travelogue_country.sql
diff --git a/backend/src/main/resources/db/migration/mysql/V6.1__add_country_code_column.sql b/backend/src/main/resources/db/migration/mysql/V6.1__add_country_code_column.sql
new file mode 100644
index 000000000..bdd635386
--- /dev/null
+++ b/backend/src/main/resources/db/migration/mysql/V6.1__add_country_code_column.sql
@@ -0,0 +1,5 @@
+ALTER TABLE travelogue_place
+    ADD COLUMN country_code VARCHAR(10);
+
+ALTER TABLE travel_plan_place
+    ADD COLUMN country_code VARCHAR(10);
diff --git a/backend/src/main/resources/db/migration/mysql/V6.2__update_country_code_none.sql b/backend/src/main/resources/db/migration/mysql/V6.2__update_country_code_none.sql
new file mode 100644
index 000000000..a22889c5d
--- /dev/null
+++ b/backend/src/main/resources/db/migration/mysql/V6.2__update_country_code_none.sql
@@ -0,0 +1,5 @@
+UPDATE travelogue_place
+SET country_code = 'NONE';
+
+UPDATE travel_plan_place
+SET country_code = 'NONE';
diff --git a/backend/src/main/resources/db/migration/mysql/V6.3__add_not_null_contraint_to_country_code.sql b/backend/src/main/resources/db/migration/mysql/V6.3__add_not_null_contraint_to_country_code.sql
new file mode 100644
index 000000000..6568f56a2
--- /dev/null
+++ b/backend/src/main/resources/db/migration/mysql/V6.3__add_not_null_contraint_to_country_code.sql
@@ -0,0 +1,5 @@
+ALTER TABLE travelogue_place
+    MODIFY country_code VARCHAR(10) NOT NULL;
+
+ALTER TABLE travel_plan_place
+    MODIFY country_code VARCHAR(10) NOT NULL;
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
index 8959594e6..395d92ab9 100644
--- a/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
@@ -22,49 +22,67 @@ class TraveloguePlaceTest {
     private static final String VALID_LNG = "126.6728";
     private static final TravelogueDay VALID_DAY = TravelogueDayFixture.TRAVELOGUE_DAY.get();
     private static final String VALID_DESC = "장소에 대한 설명";
+    private static final String VALID_COUNTRY_CODE = "KR";
 
     @DisplayName("올바른 여행기 장소 생성 시 예외가 발생하지 않는다")
     @Test
     void createTraveloguePlaceWithValidData() {
-        assertThatCode(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatCode(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .doesNotThrowAnyException();
     }
 
     @DisplayName("여행기 장소 생성 시 순서가 비어 있다면 예외가 발생한다")
     @Test
     void createTraveloguePlaceWithNullOrder() {
-        assertThatThrownBy(() -> new TraveloguePlace(null, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY))
-                .isInstanceOf(BadRequestException.class).hasMessage("여행기 장소에서 순서와 장소 위치, 그리고 방문 날짜는 비어 있을 수 없습니다");
+        assertThatThrownBy(() -> new TraveloguePlace(null, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행기 장소에서 순서와 장소 위치, 방문 날짜, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("여행기 장소 생성 시 이름 정보가 비어 있다면 예외가 발생한다")
     @Test
     void createTraveloguePlaceWithNullPlaceName() {
-        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, null, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, null, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("여행기 장소에서 순서와 장소 위치, 그리고 방문 날짜는 비어 있을 수 없습니다");
+                .hasMessage("여행기 장소에서 순서와 장소 위치, 방문 날짜, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("여행기 장소 생성 시 장소가 속한 날짜가 비어 있다면 예외가 발생한다")
     @Test
     void createTraveloguePlaceWithNullDay() {
-        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, null))
+        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, null,
+                VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("여행기 장소에서 순서와 장소 위치, 그리고 방문 날짜는 비어 있을 수 없습니다");
+                .hasMessage("여행기 장소에서 순서와 장소 위치, 방문 날짜, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("여행기 장소 생성 시 장소 설명이 비어 있더라도 여행기를 생성할 수 있다")
     @Test
     void createTraveloguePlaceWithNullDescription() {
-        assertThatCode(() -> new TraveloguePlace(VALID_ORDER, null, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatCode(() -> new TraveloguePlace(VALID_ORDER, null, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .doesNotThrowAnyException();
     }
 
+    @DisplayName("여행기 장소 생성 시 국가 코드가 비어 있다면 예외가 발생한다")
+    @Test
+    void createTraveloguePlaceWithNullCountryCode() {
+        assertThatThrownBy(
+                () -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                        null))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행기 장소에서 순서와 장소 위치, 방문 날짜, 그리고 국가 코드는 비어 있을 수 없습니다");
+    }
+
     @DisplayName("여행 장소 이름이 공백문자로만 이루어져 있는 경우 예외가 발생한다")
     @ParameterizedTest
     @ValueSource(strings = {"", "   ", "    "})
     void createTraveloguePlaceWithBlankName(String blank) {
-        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, blank, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, VALID_DESC, blank, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("장소 이름은 비어 있을 수 없습니다");
     }
@@ -73,7 +91,8 @@ void createTraveloguePlaceWithBlankName(String blank) {
     @ParameterizedTest
     @ValueSource(ints = {-1, -2, -3, -4, -5})
     void createTraveloguePlaceWithNegativeOrder(int negative) {
-        assertThatThrownBy(() -> new TraveloguePlace(negative, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatThrownBy(() -> new TraveloguePlace(negative, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("여행 장소의 순서는 음수일 수 없습니다");
     }
@@ -84,7 +103,8 @@ void createTraveloguePlaceWithInvalidLengthDescription() {
         String invalid = "서울의 명동은 현대와 전통이 조화롭게 어우러진 매력적인 지역입니다. 이곳의 거리에는 최신 패션 아이템을 갖춘 상점들이 즐비하며, 각종 뷰티 제품을 직접 체험할 수 있는 기회가 많습니다. 다양한 길거리 음식과 맛집이 가득해 미식가들의 입맛을 사로잡습니다. 서울타워와 N서울타워 전망대에서는 서울 전경을 한눈에 감상할 수 있으며, 남산 공원에서는 도심 속의 자연을 즐길 수 있습니다. 전통 시장인 남대문 시장과 청계천은 서울의 풍부한 역사와 문화를 체험할 수 있는 명소입니다. 명동의 활기 넘치는 분위기 속에서 쇼핑과 먹거리를 동시에 즐겨요!";
 
         System.out.println("length301Description = " + invalid.length());
-        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, invalid, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY))
+        assertThatThrownBy(() -> new TraveloguePlace(VALID_ORDER, invalid, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("여행 장소에 대한 설명은 300자를 넘길 수 없습니다");
     }
@@ -95,12 +115,24 @@ void createPlaceWithInvalidLengthPlaceName() {
         String length86 = "Under the warm summer sun, feeling the cool breeze by the sea is absolute pure joy!!!!";
 
         assertThatThrownBy(
-                () -> new TraveloguePlace(VALID_ORDER, VALID_DESC, length86, VALID_LAT, VALID_LNG, VALID_DAY)
+                () -> new TraveloguePlace(VALID_ORDER, VALID_DESC, length86, VALID_LAT, VALID_LNG, VALID_DAY,
+                        VALID_COUNTRY_CODE)
         )
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("장소 이름은 85자 이하여야 합니다");
     }
 
+    @DisplayName("국가 코드가 존재하지 않는 경우 장소 생성 시 예외가 발생한다")
+    @Test
+    void createPlaceWithInvalidCountryCode() {
+        assertThatThrownBy(
+                () -> new TraveloguePlace(VALID_ORDER, VALID_DESC, VALID_NAME, VALID_LAT, VALID_LNG, VALID_DAY,
+                        "SAM-572")
+        )
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("존재하지 않는 국가 코드입니다");
+    }
+
     @DisplayName("장소 사진을 추가할 수 있다")
     @Test
     void addPhotoInTraveloguePlace() {
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
index 7835417a6..dc1c359e6 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
@@ -9,7 +9,7 @@
 @AllArgsConstructor
 public enum TraveloguePlaceFixture {
 
-    TRAVELOGUE_PLACE(1, "에메랄드 빛 해변", "함덕 해수욕장", "34.54343", "126.66977", TRAVELOGUE_DAY.get()),
+    TRAVELOGUE_PLACE(1, "에메랄드 빛 해변", "함덕 해수욕장", "34.54343", "126.66977", TRAVELOGUE_DAY.get(), "KR"),
     ;
 
     private final int order;
@@ -18,12 +18,13 @@ public enum TraveloguePlaceFixture {
     private final String latitude;
     private final String longitude;
     private final TravelogueDay day;
+    private final String countryCode;
 
     public TraveloguePlace get() {
-        return new TraveloguePlace(order, description, name, latitude, longitude, day);
+        return new TraveloguePlace(order, description, name, latitude, longitude, day, countryCode);
     }
 
     public TraveloguePlace create(TravelogueDay day) {
-        return new TraveloguePlace(order, description, name, latitude, longitude, day);
+        return new TraveloguePlace(order, description, name, latitude, longitude, day, countryCode);
     }
 }
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueResponseFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueResponseFixture.java
index 6ab5f01f7..42784a1b0 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueResponseFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueResponseFixture.java
@@ -162,6 +162,7 @@ public static List<TraveloguePlaceResponse> getTraveloguePlaceResponses() {
                 .description("에메랄드 빛 해변")
                 .position(getTraveloguePositionResponse())
                 .photoUrls(getTraveloguePhotoUrls())
+                .countryCode("KR")
                 .build()
         );
     }
diff --git a/backend/src/test/java/kr/touroot/travelplan/controller/TravelPlanControllerTest.java b/backend/src/test/java/kr/touroot/travelplan/controller/TravelPlanControllerTest.java
index a6657172b..d15d6d406 100644
--- a/backend/src/test/java/kr/touroot/travelplan/controller/TravelPlanControllerTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/controller/TravelPlanControllerTest.java
@@ -70,6 +70,7 @@ void createTravelPlan() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
 
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
@@ -100,6 +101,7 @@ void createTravelPlanWithInvalidStartDate() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
         PlanRequest request = PlanRequest.builder()
@@ -255,6 +257,7 @@ void updateTravelPlan() {
         PlanPlaceRequest planPlaceRequest = PlanPlaceRequest.builder()
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
+                .countryCode("KR")
                 .position(locationRequest)
                 .build();
 
@@ -284,6 +287,7 @@ void updateTravelPlanWithNonExist() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
 
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
@@ -316,6 +320,7 @@ void updateTravelPlanWithNotAuthor() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
 
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
diff --git a/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java b/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
index b29f429ef..7c7e1cc79 100644
--- a/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
@@ -20,43 +20,58 @@ class TravelPlanPlaceTest {
     private static final String VALID_NAME = "함덕 해수욕장";
     private static final String VALID_LAT = "33.5431";
     private static final String VALID_LNG = "126.6728";
+    private static final String VALID_COUNTRY_CODE = "KR";
 
     @DisplayName("올바른 여행 계획 장소 생성 시 예외가 발생하지 않는다")
     @Test
     void createTravelPlanPlaceWithValidData() {
-        assertThatCode(() -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG))
+        assertThatCode(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .doesNotThrowAnyException();
     }
 
     @DisplayName("방문 순서가 비어 있을 경우 여행 계획 장소 생성 시 예외가 발생한다")
     @Test
     void createTravelPlanPlaceWithNullOrder() {
-        assertThatThrownBy(() -> new TravelPlanPlace(null, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(null, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("여행 계획 장소에서 순서와 날짜, 그리고 장소 위치는 비어 있을 수 없습니다");
+                .hasMessage("여행 계획 장소에서 순서와 날짜, 장소 위치, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("장소의 방문 날짜가 비어 있을 경우 여행 계획 장소 생성 시 예외가 발생한다")
     @Test
     void createTravelPlanPlaceWithNullDay() {
-        assertThatThrownBy(() -> new TravelPlanPlace(VALID_ORDER, null, VALID_NAME, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, null, VALID_NAME, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("여행 계획 장소에서 순서와 날짜, 그리고 장소 위치는 비어 있을 수 없습니다");
+                .hasMessage("여행 계획 장소에서 순서와 날짜, 장소 위치, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("장소 이름이 비어 있을 경우 여행 계획 장소 생성 시 예외가 발생한다")
     @Test
     void createTravelPlanPlaceWithPlaceNullName() {
-        assertThatThrownBy(() -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, null, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, null, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("여행 계획 장소에서 순서와 날짜, 그리고 장소 위치는 비어 있을 수 없습니다");
+                .hasMessage("여행 계획 장소에서 순서와 날짜, 장소 위치, 그리고 국가 코드는 비어 있을 수 없습니다");
+    }
+
+    @DisplayName("국가 코드가 비어 있을 경우 여행 계획 장소 생성 시 예외가 발생한다")
+    @Test
+    void createTravelPlanPlaceWithPlaceNullCountryCode() {
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, null))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행 계획 장소에서 순서와 날짜, 장소 위치, 그리고 국가 코드는 비어 있을 수 없습니다");
     }
 
     @DisplayName("여행 장소 이름이 공백문자로만 이루어져 있는 경우 예외가 발생한다")
     @ParameterizedTest
     @ValueSource(strings = {"", "   ", "    "})
     void createTravelPlanPlaceWithBlankName(String blank) {
-        assertThatThrownBy(() -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, blank, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, blank, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("장소 이름은 공백문자로만 이루어질 수 없습니다");
     }
@@ -65,7 +80,8 @@ void createTravelPlanPlaceWithBlankName(String blank) {
     @ParameterizedTest
     @ValueSource(ints = {-1, -2, -3, -4, -5})
     void createTravelPlanPlaceWithNegativeOrder(int negative) {
-        assertThatThrownBy(() -> new TravelPlanPlace(negative, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(negative, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("장소의 방문 순서는 음수일 수 없습니다");
     }
@@ -74,11 +90,21 @@ void createTravelPlanPlaceWithNegativeOrder(int negative) {
     @Test
     void createPlaceWithInvalidLengthPlaceName() {
         String length61 = "Under the summer sun, feeling the cool breeze by the sea is pure joy!!";
-        assertThatThrownBy(() -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, length61, VALID_LAT, VALID_LNG))
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, length61, VALID_LAT, VALID_LNG, VALID_COUNTRY_CODE))
                 .isInstanceOf(BadRequestException.class)
                 .hasMessage("장소 이름은 60자 이하여야 합니다");
     }
 
+    @DisplayName("존재하지 않는 국가 코드인 경우 장소 생성 시 예외가 발생한다")
+    @Test
+    void createPlaceWithInvalidCountryCode() {
+        assertThatThrownBy(
+                () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, "CONCODE"))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("존재하지 않는 국가 코드입니다");
+    }
+
     @DisplayName("Todo를 추가할 수 있다")
     @Test
     void addTodoInPlace() {
diff --git a/backend/src/test/java/kr/touroot/travelplan/fixture/TravelPlanPlaceFixture.java b/backend/src/test/java/kr/touroot/travelplan/fixture/TravelPlanPlaceFixture.java
index 24a3d4a54..360b73bfb 100644
--- a/backend/src/test/java/kr/touroot/travelplan/fixture/TravelPlanPlaceFixture.java
+++ b/backend/src/test/java/kr/touroot/travelplan/fixture/TravelPlanPlaceFixture.java
@@ -5,23 +5,26 @@
 
 public enum TravelPlanPlaceFixture {
 
-    TRAVEL_PLAN_PLACE(0, TravelPlanDayFixture.TRAVEL_PLAN_DAY.get(), "함덕 해수욕장", "34.54343", "126.66977");
+    TRAVEL_PLAN_PLACE(0, TravelPlanDayFixture.TRAVEL_PLAN_DAY.get(), "함덕 해수욕장", "34.54343", "126.66977", "KR");
 
     private final Integer order;
     private final TravelPlanDay travelPlanDay;
     private final String name;
     private final String latitude;
     private final String longitude;
+    private final String countryCode;
 
-    TravelPlanPlaceFixture(Integer order, TravelPlanDay day, String name, String latitude, String longitude) {
+    TravelPlanPlaceFixture(Integer order, TravelPlanDay day, String name, String latitude, String longitude,
+                           String countryCode) {
         this.order = order;
         this.travelPlanDay = day;
         this.name = name;
         this.latitude = latitude;
         this.longitude = longitude;
+        this.countryCode = countryCode;
     }
 
     public TravelPlanPlace get() {
-        return new TravelPlanPlace(order, travelPlanDay, name, latitude, longitude);
+        return new TravelPlanPlace(order, travelPlanDay, name, latitude, longitude, countryCode);
     }
 }
diff --git a/backend/src/test/java/kr/touroot/travelplan/helper/TravelPlanTestHelper.java b/backend/src/test/java/kr/touroot/travelplan/helper/TravelPlanTestHelper.java
index f5ee92007..17597399a 100644
--- a/backend/src/test/java/kr/touroot/travelplan/helper/TravelPlanTestHelper.java
+++ b/backend/src/test/java/kr/touroot/travelplan/helper/TravelPlanTestHelper.java
@@ -57,9 +57,10 @@ public static TravelPlanPlace getTravelPlanPlace(
             String name,
             String latitude,
             String longitude,
-            TravelPlanDay day
+            TravelPlanDay day,
+            String countryCode
     ) {
-        return new TravelPlanPlace(order, day, name, latitude, longitude);
+        return new TravelPlanPlace(order, day, name, latitude, longitude, countryCode);
     }
 
     public static TravelPlaceTodo getTravelPlaceTodo(TravelPlanPlace travelPlanPlace, String content, Integer order,
@@ -72,7 +73,7 @@ public TravelPlan initTravelPlanTestData() {
         Member author = initMemberTestData();
         TravelPlan travelPlan = getTravelPlan("여행계획", LocalDate.MAX, author);
         TravelPlanDay travelPlanDay = getTravelPlanDay(0, travelPlan);
-        TravelPlanPlace travelPlanPlace = getTravelPlanPlace(0, "장소", "37.5175896", "127.0867236", travelPlanDay);
+        TravelPlanPlace travelPlanPlace = getTravelPlanPlace(0, "장소", "37.5175896", "127.0867236", travelPlanDay, "KR");
         TravelPlaceTodo travelPlaceTodo = getTravelPlaceTodo(travelPlanPlace, "테스트짜기", 0, false);
 
         travelPlanRepository.save(travelPlan);
@@ -86,7 +87,7 @@ public TravelPlan initTravelPlanTestData() {
     public TravelPlan initTravelPlanTestData(Member author) {
         TravelPlan travelPlan = getTravelPlan("여행계획", LocalDate.MAX, author);
         TravelPlanDay travelPlanDay = getTravelPlanDay(0, travelPlan);
-        TravelPlanPlace travelPlanPlace = getTravelPlanPlace(0, "장소", "37.5175896", "127.0867236", travelPlanDay);
+        TravelPlanPlace travelPlanPlace = getTravelPlanPlace(0, "장소", "37.5175896", "127.0867236", travelPlanDay, "KR");
         TravelPlaceTodo travelPlaceTodo = getTravelPlaceTodo(travelPlanPlace, "테스트짜기", 0, false);
 
         travelPlanRepository.save(travelPlan);
diff --git a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
index 655fda9ee..483922491 100644
--- a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanFacadeServiceTest.java
@@ -77,6 +77,7 @@ void createTravelPlan() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
         PlanRequest request = PlanRequest.builder()
@@ -128,6 +129,7 @@ void updateTravelPlan() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
         PlanRequest request = PlanRequest.builder()
diff --git a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanServiceTest.java b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanServiceTest.java
index 598532dab..f2a75e1aa 100644
--- a/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/service/TravelPlanServiceTest.java
@@ -147,6 +147,7 @@ void updateTravelPlan() {
                 .placeName("잠실한강공원")
                 .todos(Collections.EMPTY_LIST)
                 .position(locationRequest)
+                .countryCode("KR")
                 .build();
         PlanDayRequest planDayRequest = new PlanDayRequest(List.of(planPlaceRequest));
         PlanRequest request = PlanRequest.builder()

From 41af9023b9a60383503a73361d2a384c6fe74be8 Mon Sep 17 00:00:00 2001
From: eunjungL <62099953+eunjungL@users.noreply.github.com>
Date: Wed, 23 Oct 2024 14:56:52 +0900
Subject: [PATCH 11/13] =?UTF-8?q?[Refactor]=20-=20=ED=86=B0=EC=BA=A3=20?=
 =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=92=20=EC=A1=B0=EC=A0=95=EC=9D=84=20?=
 =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EC=95=A0=ED=94=8C=EB=A6=AC=EC=BC=80?=
 =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=84=9C=EB=B2=84=20=EC=84=B1=EB=8A=A5=20?=
 =?UTF-8?q?=ED=8A=9C=EB=8B=9D=20(#571)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/src/main/resources/application.yml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
index f551c4692..4c7dc1837 100644
--- a/backend/src/main/resources/application.yml
+++ b/backend/src/main/resources/application.yml
@@ -36,6 +36,13 @@ management:
 spring:
   jpa:
     open-in-view: false
+
+server:
+  tomcat:
+    threads:
+      max: 20
+    max-connections: 100
+    accept-count: 50
 ---
 # local profile
 spring:

From d5747952ca988de5301215a67ece21e3797e4879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=9C=98=EC=9A=A9?=
 <99064014+slimsha2dy@users.noreply.github.com>
Date: Wed, 23 Oct 2024 16:55:32 +0900
Subject: [PATCH 12/13] =?UTF-8?q?feat:=20travelogueCountry.count=20?=
 =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EC=BF=BC=EB=A6=AC=20=EC=82=AD=EC=A0=9C=20?=
 =?UTF-8?q?(#575)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../repository/query/TravelogueQueryRepositoryImpl.java        | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
index 2094b66fb..1f8ef4dc8 100644
--- a/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
+++ b/backend/src/main/java/kr/touroot/travelogue/repository/query/TravelogueQueryRepositoryImpl.java
@@ -69,8 +69,7 @@ private void addSearchCondition(JPAQuery<Travelogue> query, SearchCondition cond
     private void findByCountryCode(JPAQuery<Travelogue> query, CountryCode countryCode) {
         query.join(travelogueCountry)
                 .on(travelogue.id.eq(travelogueCountry.travelogue.id))
-                .where(travelogueCountry.countryCode.eq(countryCode))
-                .orderBy(travelogueCountry.count.desc());
+                .where(travelogueCountry.countryCode.eq(countryCode));
     }
 
     private void findByTitleOrAuthor(SearchCondition condition, JPAQuery<Travelogue> query, String keyword) {

From 425166a05b2f5571dcc0be5f947f5e49a5f42ec2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EB=82=99=ED=97=8C?=
 <95845037+nak-honest@users.noreply.github.com>
Date: Thu, 24 Oct 2024 16:00:02 +0900
Subject: [PATCH 13/13] =?UTF-8?q?[Feature]=20-=20=EC=97=AC=ED=96=89?=
 =?UTF-8?q?=EA=B8=B0=20=EB=82=98=EB=9D=BC=20=EA=B4=80=EB=A0=A8=20=EB=A6=AC?=
 =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20(#586)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* refactor: CountryCode 내부로 검증 로직 이동

* refactor: 통일성을 위해 SearchType 의 from 메소드 수정

* feat: TravelogueCountry 검증 로직 추가

* style: 통일성을 위해 "나라"를 "국가" 로 변경

* feat: 여행기 장소 생성시 국가 코드가 NONE 인지 검증하는 로직 추가

* feat: 여행기 생성 시 국가 코드가 NONE 인 여행기 장소가 생성되지 않는 기능 구현

* feat: 태그 생성 기능 삭제

* sytle: 통일성을 위해 괄호 수정

Co-authored-by: eunjungL <62099953+eunjungL@users.noreply.github.com>

* feat: TravelogueCountry 에 NONE 국가 코드 허용

* feat: 존재하지 않는 국가로 검색 시 빈 여행기 목록을 반환하는 기능 구현

* refactor: 비즈니스 로직을 facade 가 아닌 서비스에서 수행하도록 변경

* test: 존재하지 않는 국가 검색 테스트 코드 추가

---------

Co-authored-by: eunjungL <62099953+eunjungL@users.noreply.github.com>
---
 .../touroot/tag/controller/TagController.java |  27 ---
 .../kr/touroot/tag/dto/TagCreateRequest.java  |  15 --
 .../touroot/tag/repository/TagRepository.java |   2 -
 .../kr/touroot/tag/service/TagService.java    |  17 --
 .../travelogue/domain/TravelogueCountry.java  |  22 +++
 .../travelogue/domain/TraveloguePlace.java    |   8 +-
 .../travelogue/domain/search/CountryCode.java |   9 +-
 .../domain/search/SearchCondition.java        |   4 +
 .../travelogue/domain/search/SearchType.java  |  11 +-
 .../service/TravelogueCountryService.java     |  24 +--
 .../service/TravelogueFacadeService.java      |   1 +
 .../travelogue/service/TravelogueService.java |   7 +
 .../travelplan/domain/TravelPlanPlace.java    |   4 +-
 .../kr/touroot/tag/TagControllerTest.java     |  56 -------
 .../kr/touroot/tag/fixture/TagFixture.java    |   5 -
 .../kr/touroot/tag/helper/TagTestHelper.java  |  27 ---
 .../touroot/tag/service/TagServiceTest.java   |  53 ------
 .../domain/TravelogueCountryTest.java         |  55 +++++++
 .../domain/TraveloguePlaceTest.java           |   2 +-
 .../domain/search/CountryCodeTest.java        |  22 ++-
 .../fixture/TraveloguePlaceFixture.java       |   2 +-
 .../fixture/TravelogueRequestFixture.java     |  12 ++
 .../helper/TravelogueTestHelper.java          |  26 +++
 .../service/TravelogueCountryServiceTest.java | 154 ++++++++++++++++++
 .../service/TravelogueFacadeServiceTest.java  |  22 ++-
 .../service/TravelogueServiceTest.java        |  17 ++
 .../domain/TravelPlanPlaceTest.java           |   2 +-
 27 files changed, 374 insertions(+), 232 deletions(-)
 delete mode 100644 backend/src/main/java/kr/touroot/tag/dto/TagCreateRequest.java
 delete mode 100644 backend/src/test/java/kr/touroot/tag/TagControllerTest.java
 delete mode 100644 backend/src/test/java/kr/touroot/tag/helper/TagTestHelper.java
 delete mode 100644 backend/src/test/java/kr/touroot/tag/service/TagServiceTest.java
 create mode 100644 backend/src/test/java/kr/touroot/travelogue/domain/TravelogueCountryTest.java
 create mode 100644 backend/src/test/java/kr/touroot/travelogue/service/TravelogueCountryServiceTest.java

diff --git a/backend/src/main/java/kr/touroot/tag/controller/TagController.java b/backend/src/main/java/kr/touroot/tag/controller/TagController.java
index 3dffd2e68..d1ed5e507 100644
--- a/backend/src/main/java/kr/touroot/tag/controller/TagController.java
+++ b/backend/src/main/java/kr/touroot/tag/controller/TagController.java
@@ -1,23 +1,15 @@
 package kr.touroot.tag.controller;
 
 import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.validation.Valid;
-import java.net.URI;
 import java.util.List;
-import kr.touroot.global.exception.dto.ExceptionResponse;
-import kr.touroot.tag.dto.TagCreateRequest;
 import kr.touroot.tag.dto.TagResponse;
 import kr.touroot.tag.service.TagService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -29,25 +21,6 @@ public class TagController {
 
     private final TagService tagService;
 
-    @Operation(summary = "태그 생성")
-    @ApiResponses(value = {
-            @ApiResponse(
-                    responseCode = "201",
-                    description = "태그가 생성이 정상적으로 성공했을 때"
-            ),
-            @ApiResponse(
-                    responseCode = "400",
-                    description = "Body에 유효하지 않은 값이 존재하거나 중복된 태그가 존재할 때",
-                    content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
-            )
-    })
-    @PostMapping
-    public ResponseEntity<TagResponse> createTag(@Valid @RequestBody TagCreateRequest request) {
-        TagResponse data = tagService.createTag(request);
-        return ResponseEntity.created(URI.create("/api/v1/tags/" + data.id()))
-                .body(data);
-    }
-
     @Operation(summary = "모든 태그 조회")
     @ApiResponses(value = {
             @ApiResponse(
diff --git a/backend/src/main/java/kr/touroot/tag/dto/TagCreateRequest.java b/backend/src/main/java/kr/touroot/tag/dto/TagCreateRequest.java
deleted file mode 100644
index 5c97f88ff..000000000
--- a/backend/src/main/java/kr/touroot/tag/dto/TagCreateRequest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package kr.touroot.tag.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotEmpty;
-import kr.touroot.tag.domain.Tag;
-
-public record TagCreateRequest(
-        @Schema(description = "태그 이름", example = "강아지와 함께")
-        @NotEmpty(message = "태그는 비어있을 수 없습니다.") String tag
-) {
-
-    public Tag toTag() {
-        return new Tag(tag);
-    }
-}
diff --git a/backend/src/main/java/kr/touroot/tag/repository/TagRepository.java b/backend/src/main/java/kr/touroot/tag/repository/TagRepository.java
index 23430a275..c5bfd6b2f 100644
--- a/backend/src/main/java/kr/touroot/tag/repository/TagRepository.java
+++ b/backend/src/main/java/kr/touroot/tag/repository/TagRepository.java
@@ -4,6 +4,4 @@
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface TagRepository extends JpaRepository<Tag, Long> {
-
-    boolean existsByTag(String tag);
 }
diff --git a/backend/src/main/java/kr/touroot/tag/service/TagService.java b/backend/src/main/java/kr/touroot/tag/service/TagService.java
index 645dd53c4..4a95ff97a 100644
--- a/backend/src/main/java/kr/touroot/tag/service/TagService.java
+++ b/backend/src/main/java/kr/touroot/tag/service/TagService.java
@@ -1,9 +1,6 @@
 package kr.touroot.tag.service;
 
 import java.util.List;
-import kr.touroot.global.exception.BadRequestException;
-import kr.touroot.tag.domain.Tag;
-import kr.touroot.tag.dto.TagCreateRequest;
 import kr.touroot.tag.dto.TagResponse;
 import kr.touroot.tag.repository.TagRepository;
 import lombok.RequiredArgsConstructor;
@@ -19,20 +16,6 @@ public class TagService {
 
     private final TagRepository tagRepository;
 
-    @Transactional
-    public TagResponse createTag(TagCreateRequest tagCreateRequest) {
-        validateDuplicated(tagCreateRequest);
-        Tag savedTag = tagRepository.save(tagCreateRequest.toTag());
-
-        return TagResponse.from(savedTag);
-    }
-
-    private void validateDuplicated(TagCreateRequest tagCreateRequest) {
-        if (tagRepository.existsByTag(tagCreateRequest.tag())) {
-            throw new BadRequestException("이미 존재하는 태그입니다.");
-        }
-    }
-
     @Cacheable(cacheNames = "tag")
     @Transactional(readOnly = true)
     public List<TagResponse> readTags() {
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
index 503e0b60c..a6a641d05 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/TravelogueCountry.java
@@ -10,6 +10,7 @@
 import jakarta.persistence.Id;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
+import kr.touroot.global.exception.BadRequestException;
 import kr.touroot.travelogue.domain.search.CountryCode;
 import lombok.AccessLevel;
 import lombok.AllArgsConstructor;
@@ -24,6 +25,8 @@
 @Entity
 public class TravelogueCountry {
 
+    private static final int MIN_COUNT = 1;
+
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
@@ -40,8 +43,27 @@ public class TravelogueCountry {
     private Integer count;
 
     public TravelogueCountry(Travelogue travelogue, CountryCode countryCode, Integer count) {
+        validate(travelogue, countryCode, count);
         this.travelogue = travelogue;
         this.countryCode = countryCode;
         this.count = count;
     }
+
+
+    private void validate(Travelogue travelogue, CountryCode countryCode, Integer count) {
+        validateNotNull(travelogue, countryCode, count);
+        validateCount(count);
+    }
+
+    private void validateNotNull(Travelogue travelogue, CountryCode countryCode, Integer count) {
+        if (travelogue == null || countryCode == null || count == null) {
+            throw new BadRequestException("여행기와 국가 코드, 국가 코드의 count 는 null 일 수 없습니다.");
+        }
+    }
+
+    private void validateCount(Integer count) {
+        if (count < MIN_COUNT) {
+            throw new BadRequestException(String.format("국가 코드의 개수는 %d 보다 커야합니다.", MIN_COUNT));
+        }
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java b/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
index 680a87913..bec2e4acc 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/TraveloguePlace.java
@@ -84,7 +84,7 @@ public TraveloguePlace(
         this.name = name;
         this.position = position;
         this.travelogueDay = travelogueDay;
-        this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
+        this.countryCode = CountryCode.from(countryCode);
     }
 
     public TraveloguePlace(
@@ -147,11 +147,7 @@ private void validatePlaceNameLength(String placeName) {
     }
 
     private void validateCountryCode(String countryCode) {
-        try {
-            CountryCode.valueOfIgnoreCase(countryCode);
-        } catch (IllegalArgumentException e) {
-            throw new BadRequestException("존재하지 않는 국가 코드입니다");
-        }
+        CountryCode.from(countryCode);
     }
 
     public void addPhoto(TraveloguePhoto photo) {
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
index eaf797e9f..d5ef161dd 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/CountryCode.java
@@ -2,6 +2,7 @@
 
 import java.util.Arrays;
 import java.util.Set;
+import kr.touroot.global.exception.BadRequestException;
 
 public enum CountryCode {
 
@@ -259,7 +260,11 @@ public static CountryCode findByName(String name) {
                 .orElse(NONE);
     }
 
-    public static CountryCode valueOfIgnoreCase(String name) {
-        return CountryCode.valueOf(name.toUpperCase());
+    public static CountryCode from(String code) {
+        try {
+            return CountryCode.valueOf(code.toUpperCase());
+        } catch (IllegalArgumentException exception) {
+            throw new BadRequestException("존재하지 않는 국가 코드입니다.");
+        }
     }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
index af30d3794..dc466a49f 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchCondition.java
@@ -16,4 +16,8 @@ public SearchCondition(String keyword, SearchType searchType) {
     public boolean isEmptyCondition() {
         return keyword == null && searchType == null;
     }
+
+    public boolean isNoneCountry() {
+        return searchType == SearchType.COUNTRY && CountryCode.findByName(keyword) == CountryCode.NONE;
+    }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
index 804bc6321..bfd84557f 100644
--- a/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
+++ b/backend/src/main/java/kr/touroot/travelogue/domain/search/SearchType.java
@@ -1,14 +1,15 @@
 package kr.touroot.travelogue.domain.search;
 
-import java.util.Arrays;
+import kr.touroot.global.exception.BadRequestException;
 
 public enum SearchType {
     TITLE, AUTHOR, COUNTRY;
 
     public static SearchType from(String searchType) {
-        return Arrays.stream(SearchType.values())
-                .filter(type -> searchType.equalsIgnoreCase(type.name()))
-                .findFirst()
-                .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 검색 키워드 종류입니다."));
+        try {
+            return SearchType.valueOf(searchType.toUpperCase());
+        } catch (IllegalArgumentException exception) {
+            throw new BadRequestException("존재하지 않는 검색 키워드 종류입니다.");
+        }
     }
 }
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
index 62b6de825..b28f4212c 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueCountryService.java
@@ -19,30 +19,34 @@ public class TravelogueCountryService {
 
     private final TravelogueCountryRepository travelogueCountryRepository;
 
-    @Transactional(readOnly = true)
-    public List<TravelogueCountry> readCountryByTravelogue(Travelogue travelogue) {
-        return travelogueCountryRepository.findAllByTravelogue(travelogue);
-    }
-
     @Transactional
-    public void createTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
+    public List<TravelogueCountry> createTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
         Map<CountryCode, Long> countryCounts = countCountries(request);
 
-        countryCounts.forEach((countryCode, count) -> travelogueCountryRepository.save(
-                new TravelogueCountry(travelogue, countryCode, count.intValue())));
+        return countryCounts.entrySet().stream()
+                .map(entry -> travelogueCountryRepository.save(
+                        new TravelogueCountry(travelogue, entry.getKey(), entry.getValue().intValue()))
+                 )
+                .toList();
     }
 
     private Map<CountryCode, Long> countCountries(TravelogueRequest request) {
         return request.days().stream()
                 .flatMap(day -> day.places().stream())
                 .map(place -> CountryCode.valueOf(place.countryCode()))
+                .filter(countryCode -> countryCode != CountryCode.NONE)
                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
     }
 
+    @Transactional(readOnly = true)
+    public List<TravelogueCountry> getTravelogueCountryByTravelogue(Travelogue travelogue) {
+        return travelogueCountryRepository.findAllByTravelogue(travelogue);
+    }
+
     @Transactional
-    public void updateTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
+    public List<TravelogueCountry> updateTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
         deleteAllByTravelogue(travelogue);
-        createTravelogueCountries(travelogue, request);
+        return createTravelogueCountries(travelogue, request);
     }
 
     @Transactional
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
index c87274790..cae32a9cb 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueFacadeService.java
@@ -69,6 +69,7 @@ public Page<TravelogueSimpleResponse> findSimpleTravelogues(
     ) {
         TravelogueFilterCondition filter = filterRequest.toFilterCondition();
         SearchCondition searchCondition = searchRequest.toSearchCondition();
+
         Page<Travelogue> travelogues = travelogueService.findAll(searchCondition, filter, pageable);
 
         return travelogues.map(this::getTravelogueSimpleResponse);
diff --git a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
index 48cf73f31..df8ce340d 100644
--- a/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
+++ b/backend/src/main/java/kr/touroot/travelogue/service/TravelogueService.java
@@ -45,6 +45,9 @@ public Page<Travelogue> findAllByMember(Member member, Pageable pageable) {
     public Page<Travelogue> findByKeyword(TravelogueSearchRequest request, Pageable pageable) {
         SearchType searchType = SearchType.from(request.searchType());
         SearchCondition searchCondition = new SearchCondition(request.keyword(), searchType);
+        if (searchCondition.isNoneCountry()) {
+            return Page.empty();
+        }
 
         return travelogueQueryRepository.findAllBySearchCondition(searchCondition, pageable);
     }
@@ -55,6 +58,10 @@ public Page<Travelogue> findAll(
             TravelogueFilterCondition filter,
             Pageable pageable
     ) {
+        if (searchCondition.isNoneCountry()) {
+            return Page.empty();
+        }
+
         if (filter.isEmptyCondition() && searchCondition.isEmptyCondition()) {
             return travelogueRepository.findAll(pageable);
         }
diff --git a/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java b/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
index 11af2c9fe..161068400 100644
--- a/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
+++ b/backend/src/main/java/kr/touroot/travelplan/domain/TravelPlanPlace.java
@@ -71,7 +71,7 @@ public TravelPlanPlace(Long id, Integer order, TravelPlanDay day, String name, P
         this.day = day;
         this.name = name;
         this.position = position;
-        this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
+        this.countryCode = CountryCode.from(countryCode);
     }
 
     public TravelPlanPlace(Integer order, TravelPlanDay day, String name, String latitude, String longitude,
@@ -115,7 +115,7 @@ private void validatePlaceNameLength(String placeName) {
 
     private void validateCountryCode(String countryCode) {
         try {
-            CountryCode.valueOfIgnoreCase(countryCode);
+            CountryCode.from(countryCode);
         } catch (IllegalArgumentException e) {
             throw new BadRequestException("존재하지 않는 국가 코드입니다");
         }
diff --git a/backend/src/test/java/kr/touroot/tag/TagControllerTest.java b/backend/src/test/java/kr/touroot/tag/TagControllerTest.java
deleted file mode 100644
index 53bfbfc07..000000000
--- a/backend/src/test/java/kr/touroot/tag/TagControllerTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package kr.touroot.tag;
-
-import static org.hamcrest.Matchers.is;
-
-import io.restassured.RestAssured;
-import io.restassured.http.ContentType;
-import kr.touroot.global.AcceptanceTest;
-import kr.touroot.tag.dto.TagCreateRequest;
-import kr.touroot.tag.fixture.TagFixture;
-import kr.touroot.tag.helper.TagTestHelper;
-import kr.touroot.utils.DatabaseCleaner;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.web.server.LocalServerPort;
-
-@DisplayName("태그 컨트롤러")
-@AcceptanceTest
-class TagControllerTest {
-
-    private final DatabaseCleaner databaseCleaner;
-    private final TagTestHelper testHelper;
-
-    @LocalServerPort
-    private int port;
-
-    @Autowired
-    public TagControllerTest(DatabaseCleaner databaseCleaner, TagTestHelper testHelper) {
-        this.databaseCleaner = databaseCleaner;
-        this.testHelper = testHelper;
-    }
-
-    @BeforeEach
-    void setUp() {
-        RestAssured.port = port;
-        databaseCleaner.executeTruncate();
-    }
-
-    @DisplayName("태그 컨트롤러는 태그 생성 요청 시 201을 응답한다.")
-    @Test
-    void createTag() {
-        // given
-        TagCreateRequest request = TagFixture.TAG_1.getCreateRequest();
-
-        // when & then
-        RestAssured.given().log().all()
-                .contentType(ContentType.JSON)
-                .body(request)
-                .when().log().all()
-                .post("/api/v1/tags")
-                .then().log().all()
-                .statusCode(201)
-                .header("Location", is("/api/v1/tags/1"));
-    }
-}
diff --git a/backend/src/test/java/kr/touroot/tag/fixture/TagFixture.java b/backend/src/test/java/kr/touroot/tag/fixture/TagFixture.java
index dcd3e47de..b506c705d 100644
--- a/backend/src/test/java/kr/touroot/tag/fixture/TagFixture.java
+++ b/backend/src/test/java/kr/touroot/tag/fixture/TagFixture.java
@@ -1,7 +1,6 @@
 package kr.touroot.tag.fixture;
 
 import kr.touroot.tag.domain.Tag;
-import kr.touroot.tag.dto.TagCreateRequest;
 import kr.touroot.tag.dto.TagResponse;
 
 public enum TagFixture {
@@ -21,10 +20,6 @@ public Tag get() {
         return new Tag(tag);
     }
 
-    public TagCreateRequest getCreateRequest() {
-        return new TagCreateRequest(tag);
-    }
-
     public TagResponse getResponse(Long id) {
         return new TagResponse(id, tag);
     }
diff --git a/backend/src/test/java/kr/touroot/tag/helper/TagTestHelper.java b/backend/src/test/java/kr/touroot/tag/helper/TagTestHelper.java
deleted file mode 100644
index 169ae524a..000000000
--- a/backend/src/test/java/kr/touroot/tag/helper/TagTestHelper.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package kr.touroot.tag.helper;
-
-import kr.touroot.tag.domain.Tag;
-import kr.touroot.tag.fixture.TagFixture;
-import kr.touroot.tag.repository.TagRepository;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-@Component
-public class TagTestHelper {
-
-    private final TagRepository tagRepository;
-
-    @Autowired
-    public TagTestHelper(TagRepository tagRepository) {
-        this.tagRepository = tagRepository;
-    }
-
-    public Tag initTagData() {
-        Tag tag = TagFixture.TAG_1.get();;
-        return tagRepository.save(tag);
-    }
-
-    public Tag initTagData(Tag tag) {
-        return tagRepository.save(tag);
-    }
-}
diff --git a/backend/src/test/java/kr/touroot/tag/service/TagServiceTest.java b/backend/src/test/java/kr/touroot/tag/service/TagServiceTest.java
deleted file mode 100644
index 5e30d5d06..000000000
--- a/backend/src/test/java/kr/touroot/tag/service/TagServiceTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package kr.touroot.tag.service;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import kr.touroot.global.ServiceTest;
-import kr.touroot.global.config.TestQueryDslConfig;
-import kr.touroot.global.exception.BadRequestException;
-import kr.touroot.tag.domain.Tag;
-import kr.touroot.tag.dto.TagCreateRequest;
-import kr.touroot.tag.fixture.TagFixture;
-import kr.touroot.tag.helper.TagTestHelper;
-import kr.touroot.utils.DatabaseCleaner;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Import;
-
-@DisplayName("태그 서비스")
-@Import(value = {TagService.class, TagTestHelper.class, TestQueryDslConfig.class})
-@ServiceTest
-class TagServiceTest {
-
-    private final DatabaseCleaner databaseCleaner;
-    private final TagTestHelper testHelper;
-    private final TagService tagService;
-
-    @Autowired
-    public TagServiceTest(DatabaseCleaner databaseCleaner, TagTestHelper testHelper, TagService tagService) {
-        this.databaseCleaner = databaseCleaner;
-        this.testHelper = testHelper;
-        this.tagService = tagService;
-    }
-
-    @BeforeEach
-    void setUp() {
-        databaseCleaner.executeTruncate();
-    }
-
-    @DisplayName("태그 서비스는 중복된 태그 생성 요청시 예외가 발생한다.")
-    @Test
-    void validateDuplicated() {
-        // given
-        Tag tag = TagFixture.TAG_1.get();
-        testHelper.initTagData(tag);
-        TagCreateRequest request = new TagCreateRequest(tag.getTag());
-
-        // when & then
-        assertThatThrownBy(() -> tagService.createTag(request))
-                .isInstanceOf(BadRequestException.class)
-                .hasMessage("이미 존재하는 태그입니다.");
-    }
-}
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/TravelogueCountryTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/TravelogueCountryTest.java
new file mode 100644
index 000000000..118aa893e
--- /dev/null
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/TravelogueCountryTest.java
@@ -0,0 +1,55 @@
+package kr.touroot.travelogue.domain;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import kr.touroot.global.exception.BadRequestException;
+import kr.touroot.travelogue.domain.search.CountryCode;
+import kr.touroot.travelogue.fixture.TravelogueFixture;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+class TravelogueCountryTest {
+
+    @DisplayName("검증 규칙에 어긋나지 않는 여행기 생성 시 예외가 발생하지 않는다")
+    @Test
+    void createTravelogueCountryWithValidData() {
+        assertThatCode(() -> new TravelogueCountry(TravelogueFixture.TRAVELOGUE.get(), CountryCode.KR, 1))
+                .doesNotThrowAnyException();
+    }
+
+    @DisplayName("여행기가 null인 경우 여행기 국가 생성 시 예외가 발생한다")
+    @Test
+    void createTravelogueCountryWithNullTravelogue() {
+        assertThatThrownBy(() -> new TravelogueCountry(null, CountryCode.KR, 1))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행기와 국가 코드, 국가 코드의 count 는 null 일 수 없습니다.");
+    }
+
+    @DisplayName("국가 코드가 null인 경우 여행기 국가 생성 시 예외가 발생한다")
+    @Test
+    void createTravelogueCountryWithNullCountryCode() {
+        assertThatThrownBy(() -> new TravelogueCountry(TravelogueFixture.TRAVELOGUE.get(), null, 1))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행기와 국가 코드, 국가 코드의 count 는 null 일 수 없습니다.");
+    }
+
+    @DisplayName("count가 null인 경우 여행기 국가 생성 시 예외가 발생한다")
+    @Test
+    void createTravelogueCountryWithNullCount() {
+        assertThatThrownBy(() -> new TravelogueCountry(TravelogueFixture.TRAVELOGUE.get(), CountryCode.KR, null))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("여행기와 국가 코드, 국가 코드의 count 는 null 일 수 없습니다.");
+    }
+
+    @DisplayName("count가 1보다 작은 경우 여행기 국가 생성 시 예외가 발생한다")
+    @ValueSource(ints = {0, -1})
+    @ParameterizedTest
+    void createTravelogueCountryWithLessThanMinCount(int count) {
+        assertThatThrownBy(() -> new TravelogueCountry(TravelogueFixture.TRAVELOGUE.get(), CountryCode.KR, count))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("국가 코드의 개수는 1 보다 커야합니다.");
+    }
+}
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
index 395d92ab9..19ff4b643 100644
--- a/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/TraveloguePlaceTest.java
@@ -130,7 +130,7 @@ void createPlaceWithInvalidCountryCode() {
                         "SAM-572")
         )
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("존재하지 않는 국가 코드입니다");
+                .hasMessage("존재하지 않는 국가 코드입니다.");
     }
 
     @DisplayName("장소 사진을 추가할 수 있다")
diff --git a/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
index 3f4825b4e..429110daa 100644
--- a/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/domain/search/CountryCodeTest.java
@@ -1,7 +1,9 @@
 package kr.touroot.travelogue.domain.search;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import kr.touroot.global.exception.BadRequestException;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -19,7 +21,7 @@ void findByName(String name) {
                 .isEqualTo(CountryCode.KR);
     }
 
-    @DisplayName("없는 나라 이름으로 찾으면 NONE을 반환한다.")
+    @DisplayName("없는 국가 이름으로 찾으면 NONE을 반환한다.")
     @Test
     void findByNonCountryName() {
         CountryCode code = CountryCode.findByName("미역국");
@@ -27,4 +29,22 @@ void findByNonCountryName() {
         assertThat(code)
                 .isEqualTo(CountryCode.NONE);
     }
+
+    @DisplayName("대소문자와 관계없이 국가코드로 찾을 수 있다.")
+    @ValueSource(strings = {"KR", "kr", "Kr"})
+    @ParameterizedTest
+    void from(String code) {
+        CountryCode countryCode = CountryCode.from(code);
+
+        assertThat(countryCode)
+                .isEqualTo(CountryCode.KR);
+    }
+
+    @DisplayName("존재하지 않는 국가 코드로 찾으면 예외가 발생한다.")
+    @Test
+    void fromNotExists() {
+        assertThatThrownBy(() -> CountryCode.from("WOO"))
+                .isInstanceOf(BadRequestException.class)
+                .hasMessage("존재하지 않는 국가 코드입니다.");
+    }
 }
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
index dc1c359e6..d7fa730c2 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TraveloguePlaceFixture.java
@@ -10,7 +10,7 @@
 public enum TraveloguePlaceFixture {
 
     TRAVELOGUE_PLACE(1, "에메랄드 빛 해변", "함덕 해수욕장", "34.54343", "126.66977", TRAVELOGUE_DAY.get(), "KR"),
-    ;
+    TRAVELOGUE_PLACE_WITH_NONE_COUNTRY_CODE(1, "해변", "함덕", "34.54343", "126.66977", TRAVELOGUE_DAY.get(), "NONE");
 
     private final int order;
     private final String description;
diff --git a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
index d38b3bc86..43ed8d60f 100644
--- a/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
+++ b/backend/src/test/java/kr/touroot/travelogue/fixture/TravelogueRequestFixture.java
@@ -59,6 +59,18 @@ public static List<TraveloguePlaceRequest> getTraveloguePlaceRequests(List<Trave
         ));
     }
 
+    public static List<TraveloguePlaceRequest> getTraveloguePlaceRequestsWithNoneCountryCode(
+            List<TraveloguePhotoRequest> photos) {
+        return List.of(new TraveloguePlaceRequest(
+                "함덕 해수욕장",
+                getTraveloguePositionRequest(),
+                "에메랄드 빛 해변",
+                photos,
+                "NONE"
+        ));
+    }
+
+
     public static List<TraveloguePlaceRequest> getUpdateTraveloguePlaceRequests(List<TraveloguePhotoRequest> photos) {
         return List.of(new TraveloguePlaceRequest(
                 "함덕 해수욕장",
diff --git a/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java b/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
index 60a157a9d..23a6b08c3 100644
--- a/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
+++ b/backend/src/test/java/kr/touroot/travelogue/helper/TravelogueTestHelper.java
@@ -5,6 +5,7 @@
 import static kr.touroot.travelogue.fixture.TravelogueFixture.TRAVELOGUE;
 import static kr.touroot.travelogue.fixture.TraveloguePhotoFixture.TRAVELOGUE_PHOTO;
 import static kr.touroot.travelogue.fixture.TraveloguePlaceFixture.TRAVELOGUE_PLACE;
+import static kr.touroot.travelogue.fixture.TraveloguePlaceFixture.TRAVELOGUE_PLACE_WITH_NONE_COUNTRY_CODE;
 
 import java.util.List;
 import kr.touroot.member.domain.LoginType;
@@ -79,6 +80,15 @@ public Travelogue initTravelogueTestData() {
         return initTravelogueTestData(author);
     }
 
+    public Travelogue initTravelogueTestDataWithoutCountryCode() {
+        Member author = persistMember();
+        Travelogue travelogue = persistTravelogue(author);
+        TravelogueDay day = persistTravelogueDay(travelogue);
+        TraveloguePlace place = persistTraveloguePlace(day);
+        persistTraveloguePhoto(place);
+        return travelogue;
+    }
+
     public Travelogue initTravelogueTestDataWithSeveralDays() {
         Member author = persistMember();
         return initTravelogueTestDataWithSeveralDays(author);
@@ -135,6 +145,16 @@ public Travelogue initTravelogueTestDataWithLike(Member liker) {
         return travelogue;
     }
 
+    public Travelogue initTravelogueTestDataWithNoneCountryCode() {
+        Member author = persistMember();
+        Travelogue travelogue = persistTravelogue(author);
+        TravelogueDay day = persistTravelogueDay(travelogue);
+        TraveloguePlace place = persistTraveloguePlaceWithNoneCountryCode(day);
+        persistTraveloguePhoto(place);
+
+        return travelogue;
+    }
+
     private void persisTravelogueTag(Travelogue travelogue, Tag tag) {
         Tag savedTag = initTagTestData(tag);
         travelogueTagRepository.save(new TravelogueTag(travelogue, savedTag));
@@ -164,6 +184,12 @@ public TraveloguePlace persistTraveloguePlace(TravelogueDay day) {
         return traveloguePlaceRepository.save(place);
     }
 
+    public TraveloguePlace persistTraveloguePlaceWithNoneCountryCode(TravelogueDay day) {
+        TraveloguePlace place = TRAVELOGUE_PLACE_WITH_NONE_COUNTRY_CODE.create(day);
+
+        return traveloguePlaceRepository.save(place);
+    }
+
     public TravelogueCountry persistTravelogueCountry(Travelogue travelogue) {
         TravelogueCountry travelogueCountry = TRAVELOGUE_COUNTRY.create(travelogue);
 
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueCountryServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueCountryServiceTest.java
new file mode 100644
index 000000000..9107a627b
--- /dev/null
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueCountryServiceTest.java
@@ -0,0 +1,154 @@
+package kr.touroot.travelogue.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+import java.util.List;
+import kr.touroot.global.ServiceTest;
+import kr.touroot.travelogue.domain.Travelogue;
+import kr.touroot.travelogue.domain.TravelogueCountry;
+import kr.touroot.travelogue.domain.search.CountryCode;
+import kr.touroot.travelogue.dto.request.TravelogueDayRequest;
+import kr.touroot.travelogue.dto.request.TraveloguePhotoRequest;
+import kr.touroot.travelogue.dto.request.TraveloguePlaceRequest;
+import kr.touroot.travelogue.dto.request.TravelogueRequest;
+import kr.touroot.travelogue.fixture.TravelogueRequestFixture;
+import kr.touroot.travelogue.helper.TravelogueTestHelper;
+import kr.touroot.utils.DatabaseCleaner;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Import;
+
+@DisplayName("여행기 국가 서비스")
+@Import(value = {TravelogueCountryService.class, TravelogueTestHelper.class})
+@ServiceTest
+class TravelogueCountryServiceTest {
+
+    public static final int BASIC_PAGE_SIZE = 5;
+
+    private final TravelogueCountryService travelogueCountryService;
+    private final DatabaseCleaner databaseCleaner;
+    private final TravelogueTestHelper testHelper;
+
+    @Autowired
+    public TravelogueCountryServiceTest(
+            TravelogueCountryService travelogueCountryService,
+            DatabaseCleaner databaseCleaner,
+            TravelogueTestHelper testHelper
+    ) {
+        this.travelogueCountryService = travelogueCountryService;
+        this.databaseCleaner = databaseCleaner;
+        this.testHelper = testHelper;
+    }
+
+    @BeforeEach
+    void setUp() {
+        databaseCleaner.executeTruncate();
+    }
+
+    @DisplayName("여행기 국가들을 생성할 수 있다.")
+    @Test
+    void createTravelogueCountries() {
+        // given
+        Travelogue travelogue = testHelper.initTravelogueTestDataWithoutCountryCode();
+        TravelogueRequest travelogueRequest = getTravelogueRequest();
+
+        // when
+        List<TravelogueCountry> travelogueCountries =
+                travelogueCountryService.createTravelogueCountries(travelogue, travelogueRequest);
+
+        // then
+        assertAll(
+                () -> assertThat(travelogueCountries).hasSize(1),
+                () -> assertThat(travelogueCountries.get(0).getTravelogue().getId()).isEqualTo(1L),
+                () -> assertThat(travelogueCountries.get(0).getCount()).isEqualTo(1),
+                () -> assertThat(travelogueCountries.get(0).getCountryCode()).isEqualTo(CountryCode.KR)
+        );
+    }
+
+    @DisplayName("여행기 장소의 국가 코드가 None 이면 여행기 국가가 생성되지 않는다.")
+    @Test
+    void createTravelogueCountriesWithNoneCountryCode() {
+        // given
+        Travelogue travelogue = testHelper.initTravelogueTestDataWithNoneCountryCode();
+        TravelogueRequest travelogueRequest = getTravelogueRequestWithNoneCountryCode();
+
+        // when
+        List<TravelogueCountry> travelogueCountries =
+                travelogueCountryService.createTravelogueCountries(travelogue, travelogueRequest);
+
+        // then
+        assertThat(travelogueCountries).isEmpty();
+    }
+
+    @DisplayName("여행기의 여행기 국가를 조회할 수 있다.")
+    @Test
+    void getTravelogueCountryByTravelogue() {
+        // given
+        Travelogue travelogue = testHelper.initTravelogueTestDataWithoutCountryCode();
+        TravelogueRequest travelogueRequest = getTravelogueRequest();
+        travelogueCountryService.createTravelogueCountries(travelogue, travelogueRequest);
+
+        // when
+        List<TravelogueCountry> travelogueCountries = travelogueCountryService.getTravelogueCountryByTravelogue(
+                travelogue);
+
+        // then
+        assertAll(
+                () -> assertThat(travelogueCountries).hasSize(1),
+                () -> assertThat(travelogueCountries.get(0).getTravelogue().getId()).isEqualTo(1L),
+                () -> assertThat(travelogueCountries.get(0).getCount()).isEqualTo(1),
+                () -> assertThat(travelogueCountries.get(0).getCountryCode()).isEqualTo(CountryCode.KR)
+        );
+    }
+
+    @DisplayName("여행기 국가를 업데이트 할 수 있다.")
+    @Test
+    void updateTravelogueCountries() {
+        // given
+        Travelogue travelogue = testHelper.initTravelogueTestDataWithoutCountryCode();
+        TravelogueRequest travelogueRequest = getTravelogueRequest();
+        Travelogue newTravelogue = testHelper.initTravelogueTestDataWithNoneCountryCode();
+        TravelogueRequest newTravelogueRequest = getTravelogueRequestWithNoneCountryCode();
+        travelogueCountryService.createTravelogueCountries(travelogue, travelogueRequest);
+
+        // when
+        List<TravelogueCountry> travelogueCountries =
+                travelogueCountryService.updateTravelogueCountries(newTravelogue, newTravelogueRequest);
+
+        // then
+        assertThat(travelogueCountries).isEmpty();
+    }
+
+    @DisplayName("여행기 국가를 업데이트 할 수 있다.")
+    @Test
+    void deleteAllByTravelogue() {
+        // given
+        Travelogue travelogue = testHelper.initTravelogueTestDataWithoutCountryCode();
+        TravelogueRequest travelogueRequest = getTravelogueRequest();
+        travelogueCountryService.createTravelogueCountries(travelogue, travelogueRequest);
+
+        // when
+        travelogueCountryService.deleteAllByTravelogue(travelogue);
+
+        // then
+        assertThat(travelogueCountryService.getTravelogueCountryByTravelogue(travelogue)).isEmpty();
+    }
+
+    private TravelogueRequest getTravelogueRequest() {
+        List<TraveloguePhotoRequest> photos = TravelogueRequestFixture.getTraveloguePhotoRequests();
+        List<TraveloguePlaceRequest> places = TravelogueRequestFixture.getTraveloguePlaceRequests(photos);
+        List<TravelogueDayRequest> days = TravelogueRequestFixture.getTravelogueDayRequests(places);
+        return TravelogueRequestFixture.getTravelogueRequest(days);
+    }
+
+    private TravelogueRequest getTravelogueRequestWithNoneCountryCode() {
+        List<TraveloguePhotoRequest> photos = TravelogueRequestFixture.getTraveloguePhotoRequests();
+        List<TraveloguePlaceRequest> places =
+                TravelogueRequestFixture.getTraveloguePlaceRequestsWithNoneCountryCode(photos);
+        List<TravelogueDayRequest> days = TravelogueRequestFixture.getTravelogueDayRequests(places);
+        return TravelogueRequestFixture.getTravelogueRequest(days);
+    }
+}
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
index ffb2c195d..65becd7e5 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueFacadeServiceTest.java
@@ -234,12 +234,32 @@ void findTraveloguesByCountryCodeKeyword() {
         PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
 
         // when
-        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(filterRequest, searchRequest, pageRequest);
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(filterRequest, searchRequest,
+                pageRequest);
 
         // then
         assertThat(searchResults).containsAll(responses);
     }
 
+    @DisplayName("존재하지 않는 국가를 기반으로 여행기 목록을 조회하면 빈 결과를 반환한다.")
+    @Test
+    void findTraveloguesByNoneCountryCodeKeyword() {
+        // given
+        testHelper.initAllTravelogueTestData();
+        Page<TravelogueSimpleResponse> responses = TravelogueResponseFixture.getTravelogueSimpleResponses();
+
+        TravelogueSearchRequest searchRequest = new TravelogueSearchRequest("미역국", "country");
+        TravelogueFilterRequest filterRequest = new TravelogueFilterRequest(null, null);
+        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("id"));
+
+        // when
+        Page<TravelogueSimpleResponse> searchResults = service.findSimpleTravelogues(filterRequest, searchRequest,
+                pageRequest);
+
+        // then
+        assertThat(searchResults).isEmpty();
+    }
+
     @DisplayName("여행기를 수정할 수 있다.")
     @Test
     void updateTravelogue() {
diff --git a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
index 20409b85c..5099d030f 100644
--- a/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
+++ b/backend/src/test/java/kr/touroot/travelogue/service/TravelogueServiceTest.java
@@ -125,6 +125,23 @@ void findByKeywordWithNotExistRequest() {
         assertThat(actual).isEmpty();
     }
 
+    @DisplayName("존재하지 않는 국가로 여행기를 조회하면 빈 페이지가 반환된다.")
+    @Test
+    void findByKeywordWithNotExistCountryRequest() {
+        // given
+        testHelper.initTravelogueTestData();
+
+        SearchCondition searchCondition = new SearchCondition("미역국", SearchType.TITLE);
+        TravelogueFilterCondition filter = new TravelogueFilterCondition(null, null);
+        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by("createdAt"));
+
+        // when
+        Page<Travelogue> actual = travelogueService.findAll(searchCondition, filter, pageRequest);
+
+        // then
+        assertThat(actual).isEmpty();
+    }
+
     @DisplayName("여행기를 수정할 수 있다.")
     @Test
     void updateTravelogue() {
diff --git a/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java b/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
index 7c7e1cc79..2aa2b8ba9 100644
--- a/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
+++ b/backend/src/test/java/kr/touroot/travelplan/domain/TravelPlanPlaceTest.java
@@ -102,7 +102,7 @@ void createPlaceWithInvalidCountryCode() {
         assertThatThrownBy(
                 () -> new TravelPlanPlace(VALID_ORDER, VALID_DAY, VALID_NAME, VALID_LAT, VALID_LNG, "CONCODE"))
                 .isInstanceOf(BadRequestException.class)
-                .hasMessage("존재하지 않는 국가 코드입니다");
+                .hasMessage("존재하지 않는 국가 코드입니다.");
     }
 
     @DisplayName("Todo를 추가할 수 있다")