ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,49 @@
+package nextstep.security.oauth2;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import nextstep.security.access.PathPatternRequestMatcher;
+import nextstep.security.oauth2.registration.ClientRegistration;
+import nextstep.security.oauth2.registration.ClientRegistrationRepository;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.filter.GenericFilterBean;
+
+import java.io.IOException;
+
+public class OAuth2LoginRedirectFilter extends GenericFilterBean {
+    private static final String REGISTRATION = "registration-id";
+    private static final String OAUTH_REQUEST_URI_PATTERN = "/oauth2/authorization/{" + REGISTRATION + "}";
+
+    private final ClientRegistrationRepository clientRegistrationRepository;
+    private final PathPatternRequestMatcher pathPatternRequestMatcher;
+
+    public OAuth2LoginRedirectFilter(ClientRegistrationRepository clientRegistrationRepository) {
+        this.clientRegistrationRepository = clientRegistrationRepository;
+        this.pathPatternRequestMatcher = new PathPatternRequestMatcher(HttpMethod.GET, OAUTH_REQUEST_URI_PATTERN);
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse httpServletResponse = ((HttpServletResponse) response);
+        HttpServletRequest httpServletRequest = ((HttpServletRequest) request);
+
+        if (!pathPatternRequestMatcher.matches(httpServletRequest)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        final String registrationId = pathPatternRequestMatcher.getPathVariable(httpServletRequest, REGISTRATION);
+        final ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(registrationId);
+
+        if (clientRegistration == null) {
+            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        httpServletResponse.sendRedirect(clientRegistration.getOauth2AuthorizationRedirectURl().toString());
+    }
+}

리뷰: RequestMatcher 로 한번 리팩토링 진행 해보겠습니다~
@@ -0,0 +1,49 @@
+package nextstep.security.oauth2;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import nextstep.security.access.PathPatternRequestMatcher;
+import nextstep.security.oauth2.registration.ClientRegistration;
+import nextstep.security.oauth2.registration.ClientRegistrationRepository;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.filter.GenericFilterBean;
+
+import java.io.IOException;
+
+public class OAuth2LoginRedirectFilter extends GenericFilterBean {
+    private static final String REGISTRATION = "registration-id";
+    private static final String OAUTH_REQUEST_URI_PATTERN = "/oauth2/authorization/{" + REGISTRATION + "}";
+
+    private final ClientRegistrationRepository clientRegistrationRepository;
+    private final PathPatternRequestMatcher pathPatternRequestMatcher;
+
+    public OAuth2LoginRedirectFilter(ClientRegistrationRepository clientRegistrationRepository) {
+        this.clientRegistrationRepository = clientRegistrationRepository;
+        this.pathPatternRequestMatcher = new PathPatternRequestMatcher(HttpMethod.GET, OAUTH_REQUEST_URI_PATTERN);
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse httpServletResponse = ((HttpServletResponse) response);
+        HttpServletRequest httpServletRequest = ((HttpServletRequest) request);
+
+        if (!pathPatternRequestMatcher.matches(httpServletRequest)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        final String registrationId = pathPatternRequestMatcher.getPathVariable(httpServletRequest, REGISTRATION);
+        final ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(registrationId);
+
+        if (clientRegistration == null) {
+            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        httpServletResponse.sendRedirect(clientRegistration.getOauth2AuthorizationRedirectURl().toString());
+    }
+}

리뷰: ClientRegistration를 만들다보니 

ClientRegistration 에 캡슐화하여 생성할수 있을꺼 같아서 바꾸어 보았습니다!
@@ -0,0 +1,35 @@
+package com.sparta.tentenbackend.domain.review.dto;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class CreateReviewRequestDto { // 리뷰 만들기 request
+  // 리뷰 내용
+  private String content;
+  // 리뷰 평점 1~5
+  @Min(value = 1, message = "평점은 1점 이상이어야 합니다.")
+  @Max(value = 5, message = "평점은 5점 이하이어야 합니다.")
+  private int grade;
+  // 리뷰 이미지
+  private MultipartFile file;
+
+  public CreateReviewRequestDto(String id, String content, int grade, MultipartFile file) {
+    this.content = content;
+    this.grade = grade;
+    this.file = file;
+  }
+
+//  // 회원 ID
+//  private int userId;
+
+//  // 주문 ID
+//  private String orderId;
+
+}

리뷰: 1 ~ 5점만 받도록 DTO validation이 필요해보입니다.
@@ -0,0 +1,35 @@
+package com.sparta.tentenbackend.domain.review.dto;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class CreateReviewRequestDto { // 리뷰 만들기 request
+  // 리뷰 내용
+  private String content;
+  // 리뷰 평점 1~5
+  @Min(value = 1, message = "평점은 1점 이상이어야 합니다.")
+  @Max(value = 5, message = "평점은 5점 이하이어야 합니다.")
+  private int grade;
+  // 리뷰 이미지
+  private MultipartFile file;
+
+  public CreateReviewRequestDto(String id, String content, int grade, MultipartFile file) {
+    this.content = content;
+    this.grade = grade;
+    this.file = file;
+  }
+
+//  // 회원 ID
+//  private int userId;
+
+//  // 주문 ID
+//  private String orderId;
+
+}

리뷰: 추가했습니다!
@@ -0,0 +1,35 @@
+package com.sparta.tentenbackend.domain.review.dto;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class CreateReviewRequestDto { // 리뷰 만들기 request
+  // 리뷰 내용
+  private String content;
+  // 리뷰 평점 1~5
+  @Min(value = 1, message = "평점은 1점 이상이어야 합니다.")
+  @Max(value = 5, message = "평점은 5점 이하이어야 합니다.")
+  private int grade;
+  // 리뷰 이미지
+  private MultipartFile file;
+
+  public CreateReviewRequestDto(String id, String content, int grade, MultipartFile file) {
+    this.content = content;
+    this.grade = grade;
+    this.file = file;
+  }
+
+//  // 회원 ID
+//  private int userId;
+
+//  // 주문 ID
+//  private String orderId;
+
+}

리뷰: 넵 확인하였습니다!
@@ -6,6 +6,7 @@ import kr.kro.dearmoment.image.application.command.SaveImageCommand
 import kr.kro.dearmoment.image.application.port.input.DeleteImageUseCase
 import kr.kro.dearmoment.image.application.port.input.GetImageUseCase
 import kr.kro.dearmoment.image.application.port.input.SaveImageUseCase
+import kr.kro.dearmoment.image.application.port.input.UpdateImagePort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromDBPort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromObjectStoragePort
 import kr.kro.dearmoment.image.application.port.output.GetImageFromObjectStoragePort
@@ -20,6 +21,7 @@ class ImageService(
     private val uploadImagePort: UploadImagePort,
     private val saveImagePort: SaveImagePort,
     private val getImagePort: GetImagePort,
+    private val updateImagePort: UpdateImagePort,
     private val deleteImageFromDBPort: DeleteImageFromDBPort,
     private val getImageFromObjectStorage: GetImageFromObjectStoragePort,
     private val deleteImageFromObjectStorage: DeleteImageFromObjectStoragePort,
@@ -40,21 +42,25 @@ class ImageService(
     override fun getOne(imageId: Long): GetImageResponse {
         val image = getImagePort.findOne(imageId)
 
-        if (image.isUrlExpired()) {
-            return GetImageResponse.from(getImageFromObjectStorage.getImage(image))
-        }
+        val updatedImage =
+            if (image.isUrlExpired()) {
+                val renewedImage = getImageFromObjectStorage.getImageWithUrl(image)
+                updateImagePort.updateUrlInfo(renewedImage)
+            } else {
+                image
+            }
 
-        return GetImageResponse.from(image)
+        return GetImageResponse.from(updatedImage)
     }
 
     @Transactional(readOnly = true)
     override fun getAll(userId: Long): GetImagesResponse {
-        val images = getImagePort.findAll(userId)
+        val images = getImagePort.findUserImages(userId)
 
         val finalResult =
             images.map { image ->
                 if (image.isUrlExpired()) {
-                    getImageFromObjectStorage.getImage(image)
+                    getImageFromObjectStorage.getImageWithUrl(image)
                 } else {
                     image
                 }

리뷰: ```js
@Transactional(readOnly = true)
override fun getOne(imageId: Long): GetImageResponse {
    val image = getImagePort.findOne(imageId)

    if (image.isUrlExpired()) {
        val renewedImage = getImageFromObjectStorage.getImageWithUrl(image)
        check(updateImagePort.update(renewedImage) > 0) { "fail update" }

        // 여기서 GetImageResponse.from() 호출하는 부분은,
        // 나중에 else에서도 똑같이 사용되니까 중복
        return GetImageResponse.from(renewedImage)
    }

    // 위 if 블록과 동일하게 응답 객체 만드는 코드가 있으니,
    // 중복을 줄일 수 있지 않을까요?
    return GetImageResponse.from(image)
}
```
@@ -1,5 +1,6 @@
 package kr.kro.dearmoment.image.adapter.output.persistence
 
+import kr.kro.dearmoment.image.application.port.input.UpdateImagePort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromDBPort
 import kr.kro.dearmoment.image.application.port.output.GetImagePort
 import kr.kro.dearmoment.image.application.port.output.SaveImagePort
@@ -10,7 +11,7 @@ import org.springframework.stereotype.Component
 @Component
 class ImagePersistenceAdapter(
     private val imageRepository: JpaImageRepository,
-) : SaveImagePort, DeleteImageFromDBPort, GetImagePort {
+) : SaveImagePort, UpdateImagePort, DeleteImageFromDBPort, GetImagePort {
     override fun save(image: Image): Long {
         val entity = ImageEntity.from(image)
         return imageRepository.save(entity).id
@@ -22,15 +23,20 @@ class ImagePersistenceAdapter(
             .map { it.id }
     }
 
-    override fun findAll(userId: Long): List<Image> {
-        val entities = imageRepository.findAllByUserId(userId)
-        return entities.map { ImageEntity.toDomain(it) }
-    }
+    override fun findUserImages(userId: Long): List<Image> =
+        imageRepository.findAllByUserId(userId)
+            .map { it.toDomain() }
 
     override fun findOne(imageId: Long): Image {
         val entity =
             imageRepository.findByIdOrNull(imageId) ?: throw IllegalArgumentException("Invalid imageId: $imageId")
-        return ImageEntity.toDomain(entity)
+        return entity.toDomain()
+    }
+
+    override fun updateUrlInfo(image: Image): Image {
+        val entity = imageRepository.findByIdOrNull(image.imageId) ?: throw IllegalArgumentException("Invalid imageId: ${image.imageId}")
+        entity.modifyUrlInfo(image.url, image.parId)
+        return entity.toDomain()
     }
 
     override fun delete(imageId: Long) {

리뷰: 이건 코드 리뷰가 아니라 개인적으로 궁금해서 이걸 좀 더 간결하게 쓰는 방법을 찾아보았는데요.
아래의 코드가 더 간결하고 읽기 편한가요? 그냥 코드리뷰차 공부를 해봅니다.

```js
override fun findAll(userId: Long): List<Image> =
    imageRepository.findAllByUserId(userId)
        .map { it.toDomain() } 
```
@@ -6,6 +6,7 @@ import kr.kro.dearmoment.image.application.command.SaveImageCommand
 import kr.kro.dearmoment.image.application.port.input.DeleteImageUseCase
 import kr.kro.dearmoment.image.application.port.input.GetImageUseCase
 import kr.kro.dearmoment.image.application.port.input.SaveImageUseCase
+import kr.kro.dearmoment.image.application.port.input.UpdateImagePort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromDBPort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromObjectStoragePort
 import kr.kro.dearmoment.image.application.port.output.GetImageFromObjectStoragePort
@@ -20,6 +21,7 @@ class ImageService(
     private val uploadImagePort: UploadImagePort,
     private val saveImagePort: SaveImagePort,
     private val getImagePort: GetImagePort,
+    private val updateImagePort: UpdateImagePort,
     private val deleteImageFromDBPort: DeleteImageFromDBPort,
     private val getImageFromObjectStorage: GetImageFromObjectStoragePort,
     private val deleteImageFromObjectStorage: DeleteImageFromObjectStoragePort,
@@ -40,21 +42,25 @@ class ImageService(
     override fun getOne(imageId: Long): GetImageResponse {
         val image = getImagePort.findOne(imageId)
 
-        if (image.isUrlExpired()) {
-            return GetImageResponse.from(getImageFromObjectStorage.getImage(image))
-        }
+        val updatedImage =
+            if (image.isUrlExpired()) {
+                val renewedImage = getImageFromObjectStorage.getImageWithUrl(image)
+                updateImagePort.updateUrlInfo(renewedImage)
+            } else {
+                image
+            }
 
-        return GetImageResponse.from(image)
+        return GetImageResponse.from(updatedImage)
     }
 
     @Transactional(readOnly = true)
     override fun getAll(userId: Long): GetImagesResponse {
-        val images = getImagePort.findAll(userId)
+        val images = getImagePort.findUserImages(userId)
 
         val finalResult =
             images.map { image ->
                 if (image.isUrlExpired()) {
-                    getImageFromObjectStorage.getImage(image)
+                    getImageFromObjectStorage.getImageWithUrl(image)
                 } else {
                     image
                 }

리뷰: 넵 수정해보겠습니다.
@@ -1,5 +1,6 @@
 package kr.kro.dearmoment.image.adapter.output.persistence
 
+import kr.kro.dearmoment.image.application.port.input.UpdateImagePort
 import kr.kro.dearmoment.image.application.port.output.DeleteImageFromDBPort
 import kr.kro.dearmoment.image.application.port.output.GetImagePort
 import kr.kro.dearmoment.image.application.port.output.SaveImagePort
@@ -10,7 +11,7 @@ import org.springframework.stereotype.Component
 @Component
 class ImagePersistenceAdapter(
     private val imageRepository: JpaImageRepository,
-) : SaveImagePort, DeleteImageFromDBPort, GetImagePort {
+) : SaveImagePort, UpdateImagePort, DeleteImageFromDBPort, GetImagePort {
     override fun save(image: Image): Long {
         val entity = ImageEntity.from(image)
         return imageRepository.save(entity).id
@@ -22,15 +23,20 @@ class ImagePersistenceAdapter(
             .map { it.id }
     }
 
-    override fun findAll(userId: Long): List<Image> {
-        val entities = imageRepository.findAllByUserId(userId)
-        return entities.map { ImageEntity.toDomain(it) }
-    }
+    override fun findUserImages(userId: Long): List<Image> =
+        imageRepository.findAllByUserId(userId)
+            .map { it.toDomain() }
 
     override fun findOne(imageId: Long): Image {
         val entity =
             imageRepository.findByIdOrNull(imageId) ?: throw IllegalArgumentException("Invalid imageId: $imageId")
-        return ImageEntity.toDomain(entity)
+        return entity.toDomain()
+    }
+
+    override fun updateUrlInfo(image: Image): Image {
+        val entity = imageRepository.findByIdOrNull(image.imageId) ?: throw IllegalArgumentException("Invalid imageId: ${image.imageId}")
+        entity.modifyUrlInfo(image.url, image.parId)
+        return entity.toDomain()
     }
 
     override fun delete(imageId: Long) {

리뷰: 저도 이게 항상 고민인데 디버깅을 위해서 어느정도 끊어서 써줄지 체이닝을 써줄 수 있으면 써줄지 딜레마 입니다 😅 
근데 개인적으로는 간결한걸 더 선호해서 고쳐보겠습니다.
@@ -0,0 +1,61 @@
+import axiosInstance from "@/lib/axiosInstance";
+import { useInfiniteQuery } from "@tanstack/react-query";
+
+type Gathering = {
+  teamId: number;
+  id: number;
+  type: "OFFICE_STRETCHING" | "MINDFULNESS" | "WORKATION";
+  name: string;
+  dateTime: string;
+  location: string;
+  image: string;
+};
+
+type User = {
+  teamId: number;
+  id: number;
+  name: string;
+  image: string;
+};
+
+type DataItem = {
+  teamId: number;
+  id: number;
+  score: number;
+  comment: string;
+  createdAt: string;
+  Gathering: Gathering;
+  User: User;
+};
+
+type MyReviews = {
+  data: DataItem[];
+  totalItemCount: number;
+  currentPage: number;
+  totalPages: number;
+};
+
+const fetchMyReviews = async ({ pageParam = 0, userId }: { pageParam: number; userId: number }) => {
+  const response = await axiosInstance.get<MyReviews>("reviews", {
+    params: {
+      limit: 5,
+      offset: pageParam,
+      userId,
+    },
+  });
+
+  return {
+    data: response.data,
+    nextOffset: response.data.data.length === 5 ? pageParam + 5 : null,
+  };
+};
+
+export const useGetMyReviews = (userId: number) => {
+  return useInfiniteQuery({
+    queryKey: ["mypage", "reviews", "written"],
+    queryFn: ({ pageParam }) => fetchMyReviews({ pageParam, userId }),
+    initialPageParam: 0,
+    getNextPageParam: (lastPage) => lastPage.nextOffset,
+    staleTime: 60000,
+  });
+};

리뷰: _:warning: Potential issue_

**캐시 키에 userId를 포함시켜주세요.**

현재 queryKey가 사용자별로 구분되지 않아 캐시 충돌이 발생할 수 있습니다.

```diff
 export const useGetMyReviews = (userId: number) => {
   return useInfiniteQuery({
-    queryKey: ["my-reviews"],
+    queryKey: ["my-reviews", userId],
     queryFn: ({ pageParam }) => fetchMyReviews({ pageParam, userId }),
     initialPageParam: 0,
     getNextPageParam: (lastPage) => lastPage.nextOffset,
     staleTime: 60000,
   });
 };
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export const useGetMyReviews = (userId: number) => {
  return useInfiniteQuery({
    queryKey: ["my-reviews", userId],
    queryFn: ({ pageParam }) => fetchMyReviews({ pageParam, userId }),
    initialPageParam: 0,
    getNextPageParam: (lastPage) => lastPage.nextOffset,
    staleTime: 60000,
  });
};
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
@@ -27,7 +27,8 @@ import { useGetMyGatherings } from "@/app/(common)/mypage/_hooks/useGetMyGatheri
 // isCompleted가 true, isReviewed가 true => 리뷰 작성 x
 export default function MyGatherings() {
   const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, error } = useGetMyGatherings([
-    "my-gatherings",
+    "mypage",
+    "gatherings",
   ]);
   const [isModalOpen, setModalOpen] = useState(false);
   const [selectedGathering, setSelectedGathering] = useState<number | null>(null);
@@ -40,7 +41,7 @@ export default function MyGatherings() {
     setModalOpen(false);
   };
 
-  const mutation = useLeaveGathering(["my-gatherings"]);
+  const mutation = useLeaveGathering(["gatherings"]);
 
   // 무한 스크롤을 감지할 ref
   const { observerRef } = useInfiniteScroll({

리뷰: _:hammer_and_wrench: Refactor suggestion_

**쿼리 키 구조의 일관성이 필요합니다.**

`useLeaveGathering` 훅의 쿼리 키가 `["gatherings"]`로 되어있는데, 다른 쿼리 키들과 일관성을 유지하기 위해 `["mypage", "gatherings"]`로 변경하는 것이 좋겠습니다.

```diff
-const mutation = useLeaveGathering(["gatherings"]);
+const mutation = useLeaveGathering(["mypage", "gatherings"]);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const mutation = useLeaveGathering(["mypage", "gatherings"]);
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
@@ -0,0 +1,43 @@
+import { MyGathering } from "@/app/(common)/mypage/types";
+import axiosInstance from "@/lib/axiosInstance";
+import { useInfiniteQuery } from "@tanstack/react-query";
+
+interface FetchMyGatheringsParams {
+  completed?: boolean;
+  reviewed?: boolean;
+}
+
+// 공통 데이터 가져오기 함수 (sortBy와 sortOrder는 고정)
+const fetchMyGatherings = async ({
+  pageParam = 0,
+  filters,
+}: {
+  pageParam: number;
+  filters: FetchMyGatheringsParams;
+}) => {
+  const response = await axiosInstance.get<MyGathering[]>("gatherings/joined", {
+    params: {
+      limit: 5,
+      offset: pageParam,
+      sortBy: "dateTime",
+      sortOrder: "desc",
+      completed: filters.completed,
+      reviewed: filters.reviewed,
+    },
+  });
+
+  return {
+    data: response.data,
+    nextOffset: response.data.length === 5 ? pageParam + 5 : null,
+  };
+};
+
+export const useGetMyGatherings = (queryKey: string[], filters: FetchMyGatheringsParams = {}) => {
+  return useInfiniteQuery({
+    queryKey: queryKey,
+    queryFn: ({ pageParam }) => fetchMyGatherings({ pageParam, filters }),
+    initialPageParam: 0,
+    getNextPageParam: (lastPage) => lastPage.nextOffset,
+    staleTime: 60000,
+  });
+};

리뷰: _:hammer_and_wrench: Refactor suggestion_

**불필요한 try-catch 블록을 제거하세요.**

현재 try-catch 블록이 에러를 단순히 다시 throw하고 있어 불필요합니다.

```diff
-  try {
     const response = await axiosInstance.get<MyGathering[]>("gatherings/joined", {
       params: {
         limit: 5,
         offset: pageParam,
         sortBy: "dateTime",
         sortOrder: "desc",
         completed: filters.completed,
         reviewed: filters.reviewed,
       },
     });

     return {
       data: response.data,
       nextOffset: response.data.length === 5 ? pageParam + 5 : null,
     };
-  } catch (error) {
-    throw error;
-  }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    const response = await axiosInstance.get<MyGathering[]>("gatherings/joined", {
      params: {
        limit: 5,
        offset: pageParam,
        sortBy: "dateTime",
        sortOrder: "desc",
        completed: filters.completed,
        reviewed: filters.reviewed,
      },
    });

    return {
      data: response.data,
      nextOffset: response.data.length === 5 ? pageParam + 5 : null,
    };
};
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->