Skip to content

Refactor(client): 라우팅 구조 개선 및 접근 제어 로직 리팩토링#211

Open
jyeon03 wants to merge 7 commits intodevelopfrom
refactor/routing-structure/#210
Open

Refactor(client): 라우팅 구조 개선 및 접근 제어 로직 리팩토링#211
jyeon03 wants to merge 7 commits intodevelopfrom
refactor/routing-structure/#210

Conversation

@jyeon03
Copy link
Collaborator

@jyeon03 jyeon03 commented Feb 8, 2026

📌 Summary

이번 리팩토링 수정사항은 라우트를 한 파일로 합쳤다 수준이 아니라,

Route = 기능(Domain)
Guard = 접근 정책(Policy)
Router = 조합자(Composer)

로 역할을 재정의한 구조 개선입니다. route, guard, router가 무엇인지부터 다시 생각해보고 여러 레포를 참고하여 재설계했습니다!!!

  • 기존의 publicRoutes / privateRoutes 이분법은 초기에는 직관적이지만, 서비스가 커질수록 기능이 파일 단위로 찢어지고, 예외 케이스가 누적되며 정책과 레이아웃이 강하게 결합되는 구조적 한계를 가지게 됩니다. 인증 필요/ 불필요는 route가 아닌 guard에 처리해야하기에 route를 인증을 기준으로 분리하는 것은 추후 확장성에 맞지 않다고 판단했습니다!!
    -> 이를 해결하기 위해 라우팅을 기능 중심 + 정책 조합 구조로 재설계했습니다.

📚 Tasks

  • 라우트 정의를 Public/Private 기준에서 Domain 기준으로 재구성
  • AuthGuard를 PrivateRouteGuard, PublicRouteGuard로 역할 분리
  • Router가 Guard + Layout + Domain Routes를 조합하는 구조로 변경
  • 레거시 라우트 파일 제거 및 중앙화
  • Universal Access 페이지를 예외 처리 없이 수용 가능한 구조로 변경

🔍 Describe
기존 구조의 한계

  1. 기능의 파편화
  • 기존 방식에서는 하나의 기능 안에 로그인 필요/불필요 페이지가 섞이면 라우트가 여러 파일로 분산됩니다.
  • 기능 수정 시 여러 파일을 동시에 수정해야 하며, 이는 FSD의 기능 응집 원칙과도 어긋납니다.
  1. Public / Private 이분법의 한계
    현실에는 다음과 같은 페이지들이 존재합니다.
페이지 로그인 여부
공지사항 누구나
이용약관 누구나
외부 공유 메모 누구나
  • 이 페이지들은 Public도 Private도 아닌 Universal Access 입니다. 기존 구조에서는 예외 처리를 위한 배열/플래그/조건이 계속 추가됩니다.
  1. 정책(Guard)과 레이아웃의 강한 결합
    기존 구조에서는 Public이지만 Private 레이아웃을 사용해야 하는 페이지 같은 요구를 처리하기 매우 어렵습니다. Public/Private 분류에 레이아웃과 인증 정책이 함께 묶여 있기 때문입니다.

새로운 설계의 핵심

라우팅을 3가지 책임으로 분리했습니다.

구성 책임 관심사
Route 어떤 기능인가 Domain
Guard 누가 접근 가능한가 Policy
Router 무엇을 조합할 것인가 Composition
  1. Route - 기능 단위 응집 (FSD와 정렬)

라우트가 Public/Private 기준이 아니라 기능 단위로 응집됩니다.

memo-routes.ts
ai-routes.ts
label-routes.ts
  1. Guard - 접근 정책을 컴포넌트로 분리

인증은 라우트의 속성이 아니라 통과해야 할 관문입니다.
향후 확장 가능한 정책 예

  • 관리자만 접근
  • 이메일 인증 사용자만 접근
  • 결제 사용자만 접근
  • 약관 동의 사용자만 접근
  • 온보딩 완료 사용자만 접근
    -> 배열을 늘리는 대신 Guard를 조합합니다.
  1. Router - 조합자 역할만 수행

Router는 Domain에 Guard와 Layout을 조합하는 역할만 담당합니다.

{
  Component: GuardedPrivateLayout,
  children: [...memoRoutes, ...aiRoutes]
}
  1. Universal Access 처리 (예외 없는 구조)

Guard를 적용하지 않으면 누구나 접근 가능한 페이지가 됩니다.

{
  Component: GlobalLayout,
  children: universalRoutes
}
// 예외 로직이 필요하지 않습니다.
  1. Layout과 Policy의 분리

다음과 같은 조합이 모두 자연스럽게 가능합니다.
현재 layout을 나눈 이유가 배경이 달라서였는데, 사실 public인데도 도트 이미지가 필요할 수도있고, private인데 단색 배경일 수도 있어요!! 그래서 layout에 대한 고민도 추가적으로 해봐야할 것 같아요!! 의견주시면 좋겠습니당 ‼️‼️

Guard Layout 가능 여부
없음 GlobalLayout 가능
PrivateGuard PrivateLayout 가능
PublicGuard PublicLayout 가능
PublicGuard PrivateLayout 가능
PrivateGuard GlobalLayout 가능

👀 To Reviewer

  • Domain과 Policy를 분리한 현재 구조가 장기적인 확장성 측면에서 적절한지 의견 부탁드립니다!
  • Guard 조합 방식이 향후 정책 확장에 충분히 유연한지 피드백 부탁드립니다!
  • state={{ from: location }} 패턴 도입에 대한 의견도 함께 주시면 감사하겠습니당 🥸

@jyeon03 jyeon03 requested a review from a team as a code owner February 8, 2026 16:27
@jyeon03 jyeon03 linked an issue Feb 8, 2026 that may be closed by this pull request
@jyeon03 jyeon03 requested review from jm8468, jogpfls and twossu and removed request for a team February 8, 2026 16:27
@github-actions github-actions bot added 🔨 Refactor 코드 구조 개선 🐈‍⬛ 백지연 웹 37기 백지연 labels Feb 8, 2026
@github-actions
Copy link

github-actions bot commented Feb 8, 2026

🎨 Storybook 배포 완료

PR 작성자: @jyeon03

🔗 배포된 Storybook 보기

@jogpfls jogpfls changed the title Refactor[client]: 라우팅 구조 개선 및 접근 제어 로직 리팩토링 Refactor(client): 라우팅 구조 개선 및 접근 제어 로직 리팩토링 Feb 9, 2026
Copy link
Collaborator

@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.

크으 ~ 리팩토링의 첫 PR 영광스럽네요
코멘트 몇 개 남겼는데 확인 부탁드릴게요 !! 라우팅 관련해서 함께 이야기해보고 더 좋은 구조 함께 고민해보면 좋을 것 같아요 !!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 publicRoutes, privateRoutes로 라우트를 분리하는 방식이 유지보수성과 가독성 측면에서 더 낫다고 생각해요 !!

인증 필요/불필요라는 기준이 명확한 도메인 규칙이기 때문에 오히려 지금처럼 라우트를 한 배열에 섞어두면 규모가 커질수록 분류 비용과 실수 가능성이 크다고 생각합니다 !

특히 새로운 페이지 추가 시에 이 페이지가 인증이 필요한가?를 판단하고 그 결과에 따라 private/public 중 한 곳에만 넣으면 되기 때문에 변경 범위가 작고 리뷰 포인트도 명확해진다고 생각하는데 지연님의 생각은 어떨까요 ?

또한 SSoT 위배 라고 말씀해주셨는데 분리 자체는 중복 정의가 아니라 책임 분리에 가깝다고 생각해요 !
SSoT가 실제로 깨지는 케이스는 이 페이지가 private인지 여부와 같은 동일한 규칙이 routes 파일/guard/메뉴 매핑 등 여러 곳에서 중복으로 관리되어 불일치가 생길 때인데 현재 구조는 접근 정책을 privateRoutes/publicRoutes라는 한 기준으로 모아두는 형태라 오히려 정책을 추적하기 쉽다고 생각합니다 !!

Component: PublicLayout,
children: publicRoutes,
Component: GuardedPublicLayout,
children: routes.filter((r) => !r.auth),
Copy link
Collaborator

Choose a reason for hiding this comment

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

이런식으로 filter 함수를 사용하면 가독성이 떨어질 것 같아요 ! routes 파일을 다시 분리하게 된다면 해결될 문제 같아요 !

Comment on lines 29 to 37
const { pathname } = useLocation();

const publicOnlyPaths: string[] = [
PATH.LANDING,
PATH.LOGIN,
PATH.LOGIN_CALLBACK,
];

if (accessToken && publicOnlyPaths.includes(pathname)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

const GuardedPrivateLayout = () => ( 
  <PrivateRouteGuard> 
    <PrivateLayout />
  </PrivateRouteGuard>
);

PublicRouteGuard를 PublicLayout 전체에 감싸면
PublicLayout 아래에 있는 모든 라우트가 public 영역이 되고 있기 때문에

현재 pathname이 publicOnlyPaths에 해당하나를 검사할 이유가 없을 것 같아요 !!

Copy link
Collaborator

@jm8468 jm8468 left a comment

Choose a reason for hiding this comment

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

상세하게 pr을 써주셔서 더 편하게 리뷰할 수 있었던 것 같아요👍👍👍
수고 많으셨어요!!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 publicRoutes, privateRoutes로 라우트를 분리하는 방식이 유지보수성과 가독성 측면에서 더 낫다고 생각해요 !!

인증 필요/불필요라는 기준이 명확한 도메인 규칙이기 때문에 오히려 지금처럼 라우트를 한 배열에 섞어두면 규모가 커질수록 분류 비용과 실수 가능성이 크다고 생각합니다 !

특히 새로운 페이지 추가 시에 이 페이지가 인증이 필요한가?를 판단하고 그 결과에 따라 private/public 중 한 곳에만 넣으면 되기 때문에 변경 범위가 작고 리뷰 포인트도 명확해진다고 생각하는데 지연님의 생각은 어떨까요 ?

메타데이터에 대해 잘 몰라서 메타데이터 사용과 관련해서 찾아봤습니다😊
인증 여부, 비로그인 전용, 유료 구독 여부 등으로 다양하게 메타 데이터를 입력하고, 이러한 메타데이터들을 사용해 유지보수성도 높이고, 페이지 별로 어떤 권한을 가지는 지 알 수 있어서 메타 데이터 이용에 확실한 장점이 있다고 생각해요

반대로, 저희는 현재 인증 여부(auth) 만으로 페이지를 나누고 있어서, 현 상황에서는 오히려 더 명확하게 구분이 되도록 private-route.ts, public-route.ts로 나누는 것도 장점이 있다고 생각해요

저도 다른 분들 생각이 궁금한데, 프로젝트 규모가 커질 수록 페이지 별로 역할이 어느정도 다양해질 거고, 페이지를 인증 여부 별로만 분류하지는 않을 거라고 생각합니다. 그래서 결국에 메타데이터를 사용하게 될 것 같은데, 미래를 보고 우선적으로 해야할 지, 현재 상황에 맞게 가야할 지 궁금해요!!😊😊

메타데이터 사용 시 실수를 줄이기 위해서는 작성하신 것처럼 타입을 작성해주고, 자주 사용되는 메타데이터를 default로 상정하고 코드를 작성해주는 등의 방법을 취해주면 좋을 것 같습니다!

{
path: PATH.NEW_MEMO,
Component: NewMemoPage,
auth: true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

auth-guard 방식을 auth: true일 때가 아닌 auth: false일 때를 기준으로 하는 건 어떻게 생각하시나요??
Private Routes에 있는 auth: true를 아예 없애고, Public Routes에 auth: false를 작성하는 방식입니다!

아무래도 auth: true일 때 사용되는 페이지가 많으니, 적게 사용되는 비인증 전용 페이지에만 메타데이터를 작성하는 것이 추후 생길 휴먼 에러를 더 줄일 수 있다고 생각해요😊😊👍

  // Public Routes
  {
    path: PATH.LOGIN,
    Component: LoginPage,
    meta: { auth: false },
  },
  {
    path: PATH.LOGIN_CALLBACK,
    Component: LoginCallbackPage,
    meta: { auth: false },
  },
  {
    path: PATH.LANDING,
    Component: LandingPage,
    meta: { auth: false },
  },

Copy link
Collaborator

Choose a reason for hiding this comment

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

PrivateRouteGuard, PublicRotueGuard로 나눠주셨는데, 만약 페이지가 더 늘어나고, 페이지가 인증 여부 외에도 다른 요소에 따라 보이는게 달라져야 한다면, 하나로 합치는 것이 좋을 것 같은데 어떻게 생각하시나여??

그리고 AuthGuard 내에서 토큰 유무, 메타데이터 유무를 조건으로 제어문을 작성한다면 한 곳에서 작성하므로, 분산이 적어지고, 유지보수 비용 또한 낮아질 수 있다고 생각해요

단일책임원칙에 대해서도 얘기해주셨는데, AuthGurad를 'routes/index.ts에 정의된 내용을 실행하는 역할'로 본다면 하나로 관리하는 것도 단일책임원칙에 부합하지 않을까라고 생각하고 있습니당.
책임을 더 세세하게 보고, 각각 분산한다면 오히려 응집도가 떨어지는게 아닐까라고 생각하고 있는데 다른 분들 의견도 궁금하네용

이 코멘트도 확장성을 보고 얘기드리는 거여서 오버 엔지니어링 여부를 봐야할 것 같습니다!😊😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐈‍⬛ 백지연 웹 37기 백지연 🔨 Refactor 코드 구조 개선

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 라우터 단일화 리팩토링

3 participants