Skip to content

Fix(client): User query 통합 및 게시글 수정 페이지 권한 가드#505

Merged
jeonghoon11 merged 12 commits intodevelopfrom
fix/community-edit-author/#504
Feb 25, 2026
Merged

Fix(client): User query 통합 및 게시글 수정 페이지 권한 가드#505
jeonghoon11 merged 12 commits intodevelopfrom
fix/community-edit-author/#504

Conversation

@jeonghoon11
Copy link
Member

@jeonghoon11 jeonghoon11 commented Feb 24, 2026

📌 Summary

해당 PR에 대한 작업 내용을 요약하여 작성해주세요.

  • User Query 통합
  • QUERY 통합에 따른 각 QUERY_OPTION 네이밍 변경
  • 게시글 수정 페이지 작성자 권한 가드

📚 Tasks

  • 해당 PR에 수행한 작업을 작성해주세요.

변경점이 많습니다.. PR 먼저 읽어주세요!

기존에는 게시글 작성자가 아님에도 URL을 통해 게시글 수정 페이지로 진입할 수 있는 문제가 있었어요.
이를 해결하기 위해 게시글 수정 페이지에서 작성자 권한이 있을 때에만 진입할 수 있도록 가드를 만들어야겠다고 생각했어요.

물론 본인의 게시글이 아닌 경우에 수정을 하면 서버단에서 403 에러를 보내서 막습니당

USER_QUERY_OPTIONS

사용자 정보를 받기 위해 queries 파일을 확인해보니 여러 도메인에서 getUserProfileUSER_QUERY_OPTIONS.PROFILE()이 중복 정의되어 있는 것을 발견했어요. 그래서 중복 코드를 줄이기 위해 한 곳에서 관리하는 게 낫겠다고 생각했어요.

처음에는 api/domain/user처럼 user 도메인 폴더를 만들어서 관리하려고 했어요. 하지만 현재 api/domain 폴더는 페이지 단위 도메인으로 분리되어 있어서 여기에 user를 추가하면 구조 기준이 섞일것 같았습니다.
그래서 user 관련 내용이 공통으로 사용된다는 점을 고려해 shared/api/domain/queries.ts에서 관리하도록 정리했어요.
따라서 shared/api/domain/queries.ts에서 유저 정보 조회(getUserProfile, USER_QUERY_OPTIONS.PROFILE)를 담당하도록 리팩토링했습니다.

게시글 수정 페이지 권한

이후 게시글 수정 페이지 진입을 막는 로직은 처음에는 community-edit 페이지 내부에서 구현했었어요.
처음에는 URL로 직접 접근한 경우에도 막아야 해서 라우터 레벨에서 처리할지 고민했는데 현재 구조에서 작성자 여부는 postId만으로는 알 수 없고 게시글 상세 조회 response의 writerId가 필요했어요. 그래서 community-edit 페이지에서 이미 사용하고 있는 FEED_DETAIL(postId) 응답을 활용해서 페이지 내부에서 writerIduserId를 비교하는 방식으로 먼저 구현했어요.

하지만 이 방식은 컴포넌트 내부에서 리다이렉트를 처리하게 되면서 훅 호출 순서가 렌더마다 달라질 수 있는 리스크가 있었고 권한 체크 시점도 컴포넌트 렌더링 이후라 어색했어요.

그래서 최종적으로는 community-edit 라우트의 loader에서 처리하도록 변경했어요. loader에서 FEED_DETAIL(postId)PROFILE()을 먼저 조회한 뒤, 게시글 작성자(writerId)와 현재 사용자(userId)를 비교해서 작성자가 아닌 경우 수정 페이지를 렌더링하기 전에 상세 페이지로 리다이렉트하도록 처리했어요.

추가로 작성자 비교 로직은 isPostAuthor 유틸 함수로 분리해서 커뮤니티 상세 페이지(햄버거 버튼)와 수정 페이지 권한 가드에서 동일한 로직을 재사용하도록 리팩토링했스빈다.

Backlog

기존 USER_QUERY_OPTIONS.PROFILE()가 어떤 곳은 query에서 select로 데이터를 래핑하고 있고, 아닌 곳도 있어서 이번 PR에서는 select 래핑을 제거했어요. 이후 select depth 패턴 통일 여부와 적용 기준은 다른 PR에서 작업할게요!

📸 Screenshot

[AS-IS]

2026-02-25.2.24.28.mov

[TO-BE]

2026-02-25.2.19.09.mov

@jeonghoon11 jeonghoon11 requested a review from a team as a code owner February 24, 2026 17:51
@jeonghoon11 jeonghoon11 requested review from 1jiwoo27, gwagjiug, hansoojeongsj, jogpfls and minjeoong and removed request for a team February 24, 2026 17:51
@jeonghoon11 jeonghoon11 linked an issue Feb 24, 2026 that may be closed by this pull request
@jeonghoon11 jeonghoon11 self-assigned this Feb 24, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

✅ Storybook이 배포되었습니다.
🔗 바로가기

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 말한 loader 는 createBrowserRouter 레벨에 있는 React Router 에 loader 에용

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createBrowserRouter 아래 protectedRoutes 안의 community-edit 라우트에 loader를 연결해서 페이지 컴포넌트 렌더 전에 작성자 권한을 확인하도록 구현했는데 지욱님이 말씀하시는건 community-edit과 같은 개별 라우트 레벨이 아니라 createBrowserRouter에서 ProtectedRoute가 있는 상위 route 객체 레벨에 loader를 두는 방향인가욥??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가로 작성자 권한 체크는 현재 기준으로 community-edit 라우트에서만 사용되고 있어서 우선은 상위 라우트 레벨이 아니라 community-edit 개별 라우트의 loader에서 처리 하는게 좋을것 같다고 생각했었어요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞는 것 같아요 depth 가 추가로 들어가는 구조 자체가 좀 불편하긴한데 지금 상황에선 이렇게 구현 하는게 맞을 것 같아용

@@ -0,0 +1,10 @@
export const isPostAuthor = (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const isPostAuthor = (
export const isPostAuthor = (
writerId?: number | null,
userId?: number | null,
): boolean => {
if (writerId == null || userId == null) {
return false;
}
return writerId === userId;
};

어때요?? 런타임 동작을 똑같을 탠데 boolean 을 달면 더 명확해질 것 같고 나중에 코드를 수정하다가도 반환 타입을 잘못 입력하면 컴파일 에러를 반환하도록 하는게 safe 한 것 같아서요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은것 같습니다! 함수를 읽을 때에도 가독성도 좋아지는것 같네요! 감사합니다

Copy link
Member

@gwagjiug gwagjiug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고많으셨어용

Co-authored-by: 곽지욱(クァク·ジウク) <99489686+gwagjiug@users.noreply.github.com>
Copy link
Member

@jogpfls jogpfls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

크으 ~ user query가 곳곳에 흩어져있었는데 이런 문제점을 찾다니 꼼꼼하시네요... 수고하셨습니다!!!!
JW 궁금증 남겼는데 확인해주시면 감사할 것 같아요 !

import { routePath } from '@shared/router/path';
import { queryClient } from '@shared/utils/query-client';

export const communityEditLoader = async ({ params }: LoaderFunctionArgs) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오오오 LoaderFunctionArgs 이런것도 있군요... react router loader 함수가 받는 params 인자 타입을 정의해주는 기능 처음 알아갑니다 !!

Comment on lines +17 to +20
const [feedDetailData, userData] = await Promise.all([
queryClient.ensureQueryData(COMMUNITY_QUERY_OPTIONS.FEED_DETAIL(postId)),
queryClient.ensureQueryData(USER_QUERY_OPTIONS.PROFILE()),
]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise.all을 쓰신 이유가 두개의 요청을 동시에 시작하기 위해서인가요? 만약에 한쪽 요청이 실패했을 때 전체 loader가 실패하는 동작도 의도하신 걸까요? JW입니당..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise.all을 쓰신 이유가 두개의 요청을 동시에 시작하기 위해서인가요?

네 맞아요! 두 쿼리를 Promise.all 없이 사용하면 FEED_DETAIL 먼저 받아오고 PROFILE을 받아오니 순차적으로 호출하면 시간이 더 딜레이 될것 같아요. 어차피 독립적인 요청이니 한번에 처리한게 맞습니다

@jeonghoon11 jeonghoon11 merged commit 661fcfe into develop Feb 25, 2026
@jeonghoon11 jeonghoon11 deleted the fix/community-edit-author/#504 branch February 25, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] 커뮤니티 수정 페이지 접근 작성자 가드

3 participants