UNPKG

@restnfeel/agentc-starter-kit

Version:

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

206 lines (170 loc) 5.3 kB
// 타입 정의 export * from "./types"; // 서비스 클래스 export { UserService } from "./service"; // API 핸들러 export * from "./api"; // React 컴포넌트 export { UserList, UserForm, UserStatsComponent } from "./components"; // React 훅 export { useUsers, useUser, useCreateUser, useUpdateUser, useDeleteUser, useUserStats, useBulkUserOperation, usePasswordReset, useEmailVerification, useProfileUpdate, useAccountUnlock, } from "./hooks"; // 기본 설정 export const USER_MANAGEMENT_CONFIG = { // 페이지네이션 기본값 DEFAULT_PAGE_SIZE: 20, MAX_PAGE_SIZE: 100, // 비밀번호 정책 PASSWORD_MIN_LENGTH: 8, PASSWORD_MAX_LENGTH: 128, // 계정 잠금 정책 MAX_FAILED_ATTEMPTS: 5, ACCOUNT_LOCK_DURATION: 30 * 60 * 1000, // 30분 // 토큰 만료 시간 PASSWORD_RESET_TOKEN_EXPIRY: 60 * 60 * 1000, // 1시간 EMAIL_VERIFICATION_TOKEN_EXPIRY: 24 * 60 * 60 * 1000, // 24시간 // 감사 로그 보존 기간 AUDIT_LOG_RETENTION_DAYS: 90, // 사용자 세션 설정 SESSION_TIMEOUT: 30 * 24 * 60 * 60 * 1000, // 30일 // 이메일 설정 EMAIL_VERIFICATION_REQUIRED: true, SEND_WELCOME_EMAIL: true, // 역할 기본값 DEFAULT_USER_ROLE: "VIEWER" as const, // 검색 설정 SEARCH_MIN_LENGTH: 2, SEARCH_DEBOUNCE_MS: 300, // 파일 업로드 설정 AVATAR_MAX_SIZE: 5 * 1024 * 1024, // 5MB AVATAR_ALLOWED_TYPES: ["image/jpeg", "image/png", "image/gif", "image/webp"], // 대량 작업 제한 BULK_OPERATION_MAX_USERS: 100, // 통계 캐시 시간 STATS_CACHE_DURATION: 5 * 60 * 1000, // 5분 } as const; // 유틸리티 함수 export const userUtils = { // 사용자 이름 표시 형식 getDisplayName: (user: { name: string; email: string }) => { return user.name || user.email.split("@")[0]; }, // 사용자 아바타 이니셜 getInitials: (name: string) => { return name .split(" ") .map((part) => part.charAt(0).toUpperCase()) .slice(0, 2) .join(""); }, // 계정 상태 확인 isAccountLocked: (user: { accountLockedUntil: Date | null }) => { return ( user.accountLockedUntil && new Date(user.accountLockedUntil) > new Date() ); }, // 이메일 인증 상태 확인 isEmailVerified: (user: { emailVerified: Date | null }) => { return user.emailVerified !== null; }, // 마지막 로그인 시간 포맷 formatLastLogin: (lastLogin: Date | null) => { if (!lastLogin) return "없음"; const now = new Date(); const diff = now.getTime() - new Date(lastLogin).getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) return "오늘"; if (days === 1) return "어제"; if (days < 7) return `${days}일 전`; if (days < 30) return `${Math.floor(days / 7)}주 전`; if (days < 365) return `${Math.floor(days / 30)}개월 전`; return `${Math.floor(days / 365)}년 전`; }, // 역할 표시 이름 getRoleDisplayName: (role: string) => { const roleNames = { ADMIN: "관리자", EDITOR: "에디터", VIEWER: "뷰어", GUEST: "게스트", }; return roleNames[role as keyof typeof roleNames] || role; }, // 역할 권한 레벨 getRoleLevel: (role: string) => { const roleLevels = { GUEST: 0, VIEWER: 1, EDITOR: 2, ADMIN: 3, }; return roleLevels[role as keyof typeof roleLevels] || 0; }, // 비밀번호 강도 검사 validatePasswordStrength: (password: string) => { const checks = { length: password.length >= USER_MANAGEMENT_CONFIG.PASSWORD_MIN_LENGTH, uppercase: /[A-Z]/.test(password), lowercase: /[a-z]/.test(password), number: /\d/.test(password), special: /[!@#$%^&*(),.?":{}|<>]/.test(password), }; const score = Object.values(checks).filter(Boolean).length; return { score, checks, strength: score < 2 ? "weak" : score < 4 ? "medium" : "strong", }; }, // 이메일 유효성 검사 validateEmail: (email: string) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }, // 사용자 검색 필터링 filterUsers: (users: any[], searchTerm: string) => { if ( !searchTerm || searchTerm.length < USER_MANAGEMENT_CONFIG.SEARCH_MIN_LENGTH ) { return users; } const term = searchTerm.toLowerCase(); return users.filter( (user) => user.name.toLowerCase().includes(term) || user.email.toLowerCase().includes(term) ); }, // 사용자 정렬 sortUsers: (users: any[], field: string, direction: "asc" | "desc") => { return [...users].sort((a, b) => { let aValue = a[field]; let bValue = b[field]; // 날짜 필드 처리 if (field.includes("Date") || field === "lastLogin") { aValue = aValue ? new Date(aValue).getTime() : 0; bValue = bValue ? new Date(bValue).getTime() : 0; } // 문자열 필드 처리 if (typeof aValue === "string") { aValue = aValue.toLowerCase(); bValue = bValue.toLowerCase(); } if (aValue < bValue) return direction === "asc" ? -1 : 1; if (aValue > bValue) return direction === "asc" ? 1 : -1; return 0; }); }, };