UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

373 lines (328 loc) 9.6 kB
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, })); }