Next.js에서 Clerk를 사용한 역할 기반 네비게이션 구축하기
2024-10-31 22:28:04역할 기반 네비게이션 시스템의 중요성
복잡한 웹 애플리케이션에서 사용자에게 적절한 네비게이션을 제공하는 것은 매우 중요합니다. 특히 역할 기반 네비게이션은 사용자 경험을 극대화하고 보안을 강화하는 데 필수적입니다. 이 글에서는 Next.js와 Clerk를 활용하여 효과적인 역할 기반 네비게이션 시스템을 구축하는 방법을 탐구합니다.
주요 문제점 분석
1. 복제 항목
여러 사용자 역할 간에 같은 네비게이션 항목이 반복되면 관리가 어렵습니다. 이러한 중복을 피하기 위해 중앙 집중식 데이터 관리가 필요합니다.
2. 유지보수성 하락
컨텐츠 업데이트 시, 공유 요소를 수정할 때 드러나는 코드의 복잡성을 줄이는 방법을 모색해야 합니다.
3. 접근 권한 로직의 복잡성
사용자의 역할에 따라 접근 가능한 영역이 제한되는 경우가 있습니다. 이 복잡한 접근 권한을 직관적으로 관리할 수 있어야 합니다.
4. 확장성 문제
새로운 역할이나 항목을 추가할 때 시스템의 기존 구조를 깨지 않고 유연하게 확장 가능해야 합니다.
모듈식 네비게이션 구조
정의 네비게이션 항목 만들기
네비게이션 항목을 한 곳에서 정의하여 중복을 제거하고 일관성을 유지할 수 있습니다.
// items.js
export const navItems = {
admin: {
text: "관리자 대시보드",
icon: <svg>관리자 아이콘</svg>,
href: "/dashboard/admin",
},
myTasks: {
text: "할 일",
icon: <svg>아이콘</svg>,
href: "/dashboard/todos"
},
profile: {
text: "프로필",
icon: <svg>아이콘</svg>,
href: "/dashboard/profile"
},
logout: {
text: "로그아웃",
icon: <svg>로그아웃</svg>,
logout: true
},
};
재사용 가능한 네비게이션 세트 만들기
자주 사용되는 네비게이션 구성을 미리 정의하여 코드 중복을 줄이고 유지보수를 용이하게 합니다.
// sets.js
export const navSets = {
userEssentials: ["profile", "myTasks", "logout"],
taskManagement: ["myTasks"],
adminEssentials: ["admin"],
};
네비게이션을 섹션으로 조직화
섹션을 통해 네비게이션 구조를 논리적으로 조직화하여 관리의 용이성을 높입니다.
// sections.js
import { navSets } from "./sets";
export const sections = {
admin: {
text: "관리자",
children: [...new Set([...navSets.adminEssentials])],
},
user: {
text: "사용자",
children: [...new Set([...navSets.userEssentials])],
},
};
역할 기반 접근 설정
사용자 역할과 네비게이션 섹션을 매핑하여 로직을 중앙 집중화하고 조절을 쉽게 할 수 있습니다.
// roles.js
export const roleConfig = {
"org:admin": ["admin", "user"],
"org:user": ["user"],
};
네비게이션 훅 구축
사용자 역할에 따라 적절한 네비게이션 섹션을 반환하는 커스텀 훅을 구축합니다.
// ./hooks/navigation/useNavigation.js
import { auth } from "@clerk/nextjs/server";
import { navItems } from "@/config/navigation/items";
import { sections } from "@/config/navigation/sections";
import { roleConfig } from "@/config/navigation/roles";
function getNavigationItems(userRole) {
const sectionNames = roleConfig[userRole] || roleConfig["org:user"];
return sectionNames.map(sectionName => {
const section = sections[sectionName];
return {
text: section.text,
children: section.children.map(itemKey => navItems[itemKey]),
};
});
}
export async function useNavigation() {
const { sessionClaims } = await auth();
const userRole = sessionClaims?.org_role || "org:user";
const navigationItems = getNavigationItems(userRole);
return { navigationItems };
}
이 접근 방식의 장점
- 단일 진실의 원천: 모든 네비게이션 항목을 한 번만 정의하여 중복을 줄입니다.
- 구성 가능한 구조: 기존 세트를 재사용하여 쉽게 새로운 섹션을 만들 수 있습니다.
- 간단한 유지 보수: 공유 항목은 한 곳에서만 업데이트하면 됩니다.
- 확장성: 새로운 역할이나 네비게이션 항목 추가가 수월합니다.
- 타입 안전성: 키 사용으로 자동 완성 및 오타 방지 가능.
실제 사용 사례
이 구조를 Sidebar 컴포넌트에서 활용하는 예시입니다.
// Sidebar.js
import { useNavigation } from "@/hooks/useNavigation";
function Sidebar() {
const { navigationItems } = useNavigation();
return (
<nav>
{navigationItems.map((section) => (
<div key={section.text}>
<h2>{section.text}</h2>
<ul>
{section.children.map((item) => (
<li key={item.text}>
<Link href={item.href}>
{item.icon}
{item.text}
</Link>
</li>
))}
</ul>
</div>
))}
</nav>
);
}
베스트 프랙티스
네비게이션을 체계적으로 유지하고 관리하기 위해 다음의 팁을 참고하세요.
- 구성 폴더에 네비게이션 항목 저장: 항목들을 별도 폴더에 저장하여 구조화 및 유지 보수를 용이하게 합니다.
- 설명적인 이름 사용: 네비게이션 세트와 섹션에 대해 설명적인 이름을 사용하세요.
- 중복 방지: Set을 사용하여 중복 항목을 방지하세요.
- 알 수 없는 사용자에 대한 기본값 설정: 권한이 없는 사용자나 예상치 못한 사용자를 위한 기본 네비게이션을 설정합니다.
이 접근 방식은 복잡한 네비게이션 구조를 효과적으로 관리하며, 다양한 사용자 역할에 따라 유연하게 확장 가능한 시스템을 구축하는 데 적합합니다.