@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
373 lines (328 loc) • 9.6 kB
text/typescript
import { UserRole } from "./middleware";
// 권한 타입 정의
export enum Permission {
// 사용자 관리
USER_CREATE = "user:create",
USER_READ = "user:read",
USER_UPDATE = "user:update",
USER_DELETE = "user:delete",
USER_MANAGE_ROLES = "user:manage_roles",
// 사이트 관리
SITE_CREATE = "site:create",
SITE_READ = "site:read",
SITE_UPDATE = "site:update",
SITE_DELETE = "site:delete",
SITE_PUBLISH = "site:publish",
// 섹션/페이지 관리
SECTION_CREATE = "section:create",
SECTION_READ = "section:read",
SECTION_UPDATE = "section:update",
SECTION_DELETE = "section:delete",
SECTION_PUBLISH = "section:publish",
// 템플릿 관리
TEMPLATE_CREATE = "template:create",
TEMPLATE_READ = "template:read",
TEMPLATE_UPDATE = "template:update",
TEMPLATE_DELETE = "template:delete",
TEMPLATE_PUBLISH = "template:publish",
// 파일 관리
FILE_UPLOAD = "file:upload",
FILE_READ = "file:read",
FILE_DELETE = "file:delete",
// 시스템 관리
SYSTEM_SETTINGS = "system:settings",
SYSTEM_AUDIT = "system:audit",
SYSTEM_BACKUP = "system:backup",
// 테넌트 관리
TENANT_CREATE = "tenant:create",
TENANT_READ = "tenant:read",
TENANT_UPDATE = "tenant:update",
TENANT_DELETE = "tenant:delete",
}
// 역할별 권한 매핑
export const ROLE_PERMISSIONS: Record<UserRole, Permission[]> = {
[UserRole.ADMIN]: [
// 모든 권한
...Object.values(Permission),
],
[UserRole.EDITOR]: [
// 사용자 읽기
Permission.USER_READ,
// 사이트 관리 (삭제 제외)
Permission.SITE_CREATE,
Permission.SITE_READ,
Permission.SITE_UPDATE,
Permission.SITE_PUBLISH,
// 섹션 관리
Permission.SECTION_CREATE,
Permission.SECTION_READ,
Permission.SECTION_UPDATE,
Permission.SECTION_DELETE,
Permission.SECTION_PUBLISH,
// 템플릿 관리
Permission.TEMPLATE_CREATE,
Permission.TEMPLATE_READ,
Permission.TEMPLATE_UPDATE,
Permission.TEMPLATE_DELETE,
Permission.TEMPLATE_PUBLISH,
// 파일 관리
Permission.FILE_UPLOAD,
Permission.FILE_READ,
Permission.FILE_DELETE,
],
[UserRole.VIEWER]: [
// 읽기 전용 권한
Permission.USER_READ,
Permission.SITE_READ,
Permission.SECTION_READ,
Permission.TEMPLATE_READ,
Permission.FILE_READ,
],
[UserRole.GUEST]: [
// 공개 콘텐츠만 읽기
Permission.SITE_READ,
Permission.SECTION_READ,
],
};
// 리소스별 권한 그룹
export const RESOURCE_PERMISSIONS = {
USER: [
Permission.USER_CREATE,
Permission.USER_READ,
Permission.USER_UPDATE,
Permission.USER_DELETE,
Permission.USER_MANAGE_ROLES,
],
SITE: [
Permission.SITE_CREATE,
Permission.SITE_READ,
Permission.SITE_UPDATE,
Permission.SITE_DELETE,
Permission.SITE_PUBLISH,
],
SECTION: [
Permission.SECTION_CREATE,
Permission.SECTION_READ,
Permission.SECTION_UPDATE,
Permission.SECTION_DELETE,
Permission.SECTION_PUBLISH,
],
TEMPLATE: [
Permission.TEMPLATE_CREATE,
Permission.TEMPLATE_READ,
Permission.TEMPLATE_UPDATE,
Permission.TEMPLATE_DELETE,
Permission.TEMPLATE_PUBLISH,
],
FILE: [Permission.FILE_UPLOAD, Permission.FILE_READ, Permission.FILE_DELETE],
SYSTEM: [
Permission.SYSTEM_SETTINGS,
Permission.SYSTEM_AUDIT,
Permission.SYSTEM_BACKUP,
],
TENANT: [
Permission.TENANT_CREATE,
Permission.TENANT_READ,
Permission.TENANT_UPDATE,
Permission.TENANT_DELETE,
],
};
/**
* 사용자 역할에 특정 권한이 있는지 확인
*/
export function hasPermission(
userRole: UserRole,
permission: Permission
): boolean {
const rolePermissions = ROLE_PERMISSIONS[userRole];
return rolePermissions.includes(permission);
}
/**
* 사용자 역할에 여러 권한이 모두 있는지 확인
*/
export function hasAllPermissions(
userRole: UserRole,
permissions: Permission[]
): boolean {
return permissions.every((permission) => hasPermission(userRole, permission));
}
/**
* 사용자 역할에 권한 중 하나라도 있는지 확인
*/
export function hasAnyPermission(
userRole: UserRole,
permissions: Permission[]
): boolean {
return permissions.some((permission) => hasPermission(userRole, permission));
}
/**
* 특정 리소스에 대한 권한 확인
*/
export function hasResourcePermission(
userRole: UserRole,
resource: keyof typeof RESOURCE_PERMISSIONS,
action:
| "create"
| "read"
| "update"
| "delete"
| "publish"
| "manage_roles"
| "upload"
): boolean {
const resourcePermissions = RESOURCE_PERMISSIONS[resource];
const permission = resourcePermissions.find((p) => p.includes(action));
if (!permission) {
return false;
}
return hasPermission(userRole, permission);
}
/**
* 사용자가 다른 사용자를 관리할 수 있는지 확인
*/
export function canManageUser(
managerRole: UserRole,
targetRole: UserRole
): boolean {
// 관리자는 모든 사용자 관리 가능
if (managerRole === UserRole.ADMIN) {
return true;
}
// 편집자는 뷰어와 게스트만 관리 가능
if (managerRole === UserRole.EDITOR) {
return targetRole === UserRole.VIEWER || targetRole === UserRole.GUEST;
}
// 뷰어와 게스트는 다른 사용자 관리 불가
return false;
}
/**
* 역할 계층 구조 확인
*/
export function isHigherRole(role1: UserRole, role2: UserRole): boolean {
const roleHierarchy = {
[UserRole.ADMIN]: 4,
[UserRole.EDITOR]: 3,
[UserRole.VIEWER]: 2,
[UserRole.GUEST]: 1,
};
return roleHierarchy[role1] > roleHierarchy[role2];
}
/**
* 권한 기반 필터링
*/
export function filterByPermission<
T extends { userId?: string; createdById?: string }
>(items: T[], userRole: UserRole, userId: string, permission: Permission): T[] {
// 권한이 없으면 빈 배열 반환
if (!hasPermission(userRole, permission)) {
return [];
}
// 관리자는 모든 항목 접근 가능
if (userRole === UserRole.ADMIN) {
return items;
}
// 편집자는 자신이 생성한 항목과 뷰어가 생성한 항목 접근 가능
if (userRole === UserRole.EDITOR) {
return items.filter(
(item) =>
item.userId === userId ||
item.createdById === userId ||
// 뷰어가 생성한 항목도 편집 가능 (별도 로직 필요)
true
);
}
// 뷰어는 자신이 생성한 항목만 접근 가능
if (userRole === UserRole.VIEWER) {
return items.filter(
(item) => item.userId === userId || item.createdById === userId
);
}
// 게스트는 공개 항목만 접근 가능
return [];
}
/**
* API 엔드포인트별 필요 권한 매핑
*/
export const API_PERMISSIONS: Record<string, Permission[]> = {
// 사용자 관리 API
"POST /api/users": [Permission.USER_CREATE],
"GET /api/users": [Permission.USER_READ],
"PUT /api/users/:id": [Permission.USER_UPDATE],
"DELETE /api/users/:id": [Permission.USER_DELETE],
"PUT /api/users/:id/role": [Permission.USER_MANAGE_ROLES],
// 사이트 관리 API
"POST /api/sites": [Permission.SITE_CREATE],
"GET /api/sites": [Permission.SITE_READ],
"PUT /api/sites/:id": [Permission.SITE_UPDATE],
"DELETE /api/sites/:id": [Permission.SITE_DELETE],
"POST /api/sites/:id/publish": [Permission.SITE_PUBLISH],
// 섹션 관리 API
"POST /api/sections": [Permission.SECTION_CREATE],
"GET /api/sections": [Permission.SECTION_READ],
"PUT /api/sections/:id": [Permission.SECTION_UPDATE],
"DELETE /api/sections/:id": [Permission.SECTION_DELETE],
"POST /api/sections/:id/publish": [Permission.SECTION_PUBLISH],
// 템플릿 관리 API
"POST /api/templates": [Permission.TEMPLATE_CREATE],
"GET /api/templates": [Permission.TEMPLATE_READ],
"PUT /api/templates/:id": [Permission.TEMPLATE_UPDATE],
"DELETE /api/templates/:id": [Permission.TEMPLATE_DELETE],
"POST /api/templates/:id/publish": [Permission.TEMPLATE_PUBLISH],
// 파일 관리 API
"POST /api/files/upload": [Permission.FILE_UPLOAD],
"GET /api/files": [Permission.FILE_READ],
"DELETE /api/files/:id": [Permission.FILE_DELETE],
// 시스템 관리 API
"GET /api/admin/settings": [Permission.SYSTEM_SETTINGS],
"PUT /api/admin/settings": [Permission.SYSTEM_SETTINGS],
"GET /api/admin/audit": [Permission.SYSTEM_AUDIT],
"POST /api/admin/backup": [Permission.SYSTEM_BACKUP],
};
/**
* API 경로에 대한 권한 확인
*/
export function hasApiPermission(
userRole: UserRole,
method: string,
path: string
): boolean {
const apiKey = `${method} ${path}`;
const requiredPermissions = API_PERMISSIONS[apiKey];
if (!requiredPermissions) {
// 정의되지 않은 API는 기본적으로 접근 거부
return false;
}
return hasAnyPermission(userRole, requiredPermissions);
}
/**
* 권한 기반 UI 컴포넌트 표시 여부 결정
*/
export function shouldShowComponent(
userRole: UserRole,
requiredPermissions: Permission[]
): boolean {
return hasAnyPermission(userRole, requiredPermissions);
}
/**
* 권한 기반 메뉴 필터링
*/
export interface MenuItem {
id: string;
label: string;
path: string;
requiredPermissions: Permission[];
children?: MenuItem[];
}
export function filterMenuItems(
menuItems: MenuItem[],
userRole: UserRole
): MenuItem[] {
return menuItems
.filter((item) => hasAnyPermission(userRole, item.requiredPermissions))
.map((item) => ({
...item,
children: item.children
? filterMenuItems(item.children, userRole)
: undefined,
}));
}