@k-msg/channel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -0
- package/dist/index.cjs +2466 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +837 -0
- package/dist/index.d.ts +837 -0
- package/dist/index.js +2417 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/channel.types.ts","../src/kakao/channel.ts","../src/kakao/sender-number.ts","../src/management/crud.ts","../src/management/permissions.ts","../src/verification/business.verify.ts","../src/verification/number.verify.ts","../src/services/channel.service.ts"],"sourcesContent":["// Types\nexport * from './types/channel.types';\n\n// Kakao Channel Management\nexport { KakaoChannelManager } from './kakao/channel';\nexport { KakaoSenderNumberManager } from './kakao/sender-number';\n\n// Channel Management\nexport { \n ChannelCRUD,\n type PaginationOptions,\n type PaginatedResult,\n type ChannelCRUDOptions,\n type AuditLogEntry\n} from './management/crud';\n\nexport { \n PermissionManager,\n type User,\n type Role,\n type Permission,\n type AccessContext,\n type PermissionCheck,\n type PermissionResult,\n ResourceType,\n ActionType,\n PermissionScope\n} from './management/permissions';\n\n// Verification Systems\nexport { \n BusinessVerifier,\n type BusinessInfo,\n type VerificationRequest,\n type AutoVerificationResult,\n type DocumentValidationResult,\n type BusinessVerifierOptions\n} from './verification/business.verify';\n\nexport { \n NumberVerifier,\n type PhoneVerificationRequest,\n type VerificationAttempt,\n type PhoneVerificationStatus,\n type NumberVerifierOptions,\n type SMSProvider,\n type VoiceProvider,\n type PhoneNumberInfo,\n VerificationType,\n VerificationMethod\n} from './verification/number.verify';\n\n// Legacy Channel Service (maintained for backward compatibility)\nexport { ChannelService } from './services/channel.service';","import { z } from 'zod';\n\nexport interface Channel {\n id: string;\n name: string;\n provider: string;\n type: ChannelType;\n status: ChannelStatus;\n profileKey: string;\n senderNumbers: SenderNumber[];\n metadata: ChannelMetadata;\n verification: ChannelVerification;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport enum ChannelType {\n KAKAO_ALIMTALK = 'KAKAO_ALIMTALK',\n KAKAO_FRIENDTALK = 'KAKAO_FRIENDTALK',\n SMS = 'SMS',\n LMS = 'LMS',\n MMS = 'MMS'\n}\n\nexport enum ChannelStatus {\n PENDING = 'PENDING', // 등록 대기\n VERIFYING = 'VERIFYING', // 검증 중\n ACTIVE = 'ACTIVE', // 활성화\n SUSPENDED = 'SUSPENDED', // 일시 정지\n BLOCKED = 'BLOCKED', // 차단됨\n DELETED = 'DELETED' // 삭제됨\n}\n\nexport interface SenderNumber {\n id: string;\n phoneNumber: string;\n status: SenderNumberStatus;\n verificationCode?: string;\n verifiedAt?: Date;\n category: SenderNumberCategory;\n metadata: {\n businessName?: string;\n businessRegistrationNumber?: string;\n contactPerson?: string;\n contactEmail?: string;\n };\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport enum SenderNumberStatus {\n PENDING = 'PENDING', // 등록 대기\n VERIFYING = 'VERIFYING', // 인증 중\n VERIFIED = 'VERIFIED', // 인증 완료\n REJECTED = 'REJECTED', // 반려됨\n BLOCKED = 'BLOCKED' // 차단됨\n}\n\nexport enum SenderNumberCategory {\n BUSINESS = 'BUSINESS', // 사업자\n PERSONAL = 'PERSONAL', // 개인\n GOVERNMENT = 'GOVERNMENT', // 관공서\n NON_PROFIT = 'NON_PROFIT' // 비영리단체\n}\n\nexport interface ChannelMetadata {\n businessInfo?: {\n name: string;\n registrationNumber: string;\n category: string;\n contactPerson: string;\n contactEmail: string;\n contactPhone: string;\n };\n kakaoInfo?: {\n plusFriendId: string;\n brandName: string;\n logoUrl?: string;\n description?: string;\n };\n limits: {\n dailyMessageLimit: number;\n monthlyMessageLimit: number;\n rateLimit: number; // messages per second\n };\n features: {\n supportsBulkSending: boolean;\n supportsScheduling: boolean;\n supportsButtons: boolean;\n maxButtonCount: number;\n };\n}\n\nexport interface ChannelVerification {\n status: VerificationStatus;\n documents: VerificationDocument[];\n verifiedAt?: Date;\n rejectedAt?: Date;\n rejectionReason?: string;\n verifiedBy?: string;\n}\n\nexport enum VerificationStatus {\n NOT_REQUIRED = 'NOT_REQUIRED',\n PENDING = 'PENDING',\n UNDER_REVIEW = 'UNDER_REVIEW',\n VERIFIED = 'VERIFIED',\n REJECTED = 'REJECTED'\n}\n\nexport interface VerificationDocument {\n id: string;\n type: DocumentType;\n fileName: string;\n fileUrl: string;\n uploadedAt: Date;\n status: DocumentStatus;\n}\n\nexport enum DocumentType {\n BUSINESS_REGISTRATION = 'BUSINESS_REGISTRATION',\n BUSINESS_LICENSE = 'BUSINESS_LICENSE',\n ID_CARD = 'ID_CARD',\n AUTHORIZATION_LETTER = 'AUTHORIZATION_LETTER',\n OTHER = 'OTHER'\n}\n\nexport enum DocumentStatus {\n UPLOADED = 'UPLOADED',\n VERIFIED = 'VERIFIED',\n REJECTED = 'REJECTED'\n}\n\n// Request/Response types\nexport interface ChannelCreateRequest {\n name: string;\n type: ChannelType;\n provider: string;\n profileKey: string;\n businessInfo?: {\n name: string;\n registrationNumber: string;\n category: string;\n contactPerson: string;\n contactEmail: string;\n contactPhone: string;\n };\n kakaoInfo?: {\n plusFriendId: string;\n brandName: string;\n logoUrl?: string;\n description?: string;\n };\n}\n\nexport interface SenderNumberCreateRequest {\n phoneNumber: string;\n category: SenderNumberCategory;\n businessInfo?: {\n businessName: string;\n businessRegistrationNumber: string;\n contactPerson: string;\n contactEmail: string;\n };\n}\n\nexport interface ChannelFilters {\n provider?: string;\n type?: ChannelType;\n status?: ChannelStatus;\n verified?: boolean;\n createdAfter?: Date;\n createdBefore?: Date;\n}\n\nexport interface SenderNumberFilters {\n channelId?: string;\n status?: SenderNumberStatus;\n category?: SenderNumberCategory;\n verified?: boolean;\n}\n\n// Zod schemas\nexport const ChannelCreateRequestSchema = z.object({\n name: z.string().min(1).max(100),\n type: z.nativeEnum(ChannelType),\n provider: z.string().min(1),\n profileKey: z.string().min(1),\n businessInfo: z.object({\n name: z.string().min(1),\n registrationNumber: z.string().min(1),\n category: z.string().min(1),\n contactPerson: z.string().min(1),\n contactEmail: z.string().email(),\n contactPhone: z.string().regex(/^[0-9-+\\s()]+$/),\n }).optional(),\n kakaoInfo: z.object({\n plusFriendId: z.string().min(1),\n brandName: z.string().min(1),\n logoUrl: z.string().url().optional(),\n description: z.string().max(500).optional(),\n }).optional(),\n});\n\nexport const SenderNumberCreateRequestSchema = z.object({\n phoneNumber: z.string().regex(/^[0-9]{10,11}$/),\n category: z.nativeEnum(SenderNumberCategory),\n businessInfo: z.object({\n businessName: z.string().min(1),\n businessRegistrationNumber: z.string().min(1),\n contactPerson: z.string().min(1),\n contactEmail: z.string().email(),\n }).optional(),\n});\n\nexport const ChannelFiltersSchema = z.object({\n provider: z.string().optional(),\n type: z.nativeEnum(ChannelType).optional(),\n status: z.nativeEnum(ChannelStatus).optional(),\n verified: z.boolean().optional(),\n createdAfter: z.date().optional(),\n createdBefore: z.date().optional(),\n});\n\nexport const SenderNumberFiltersSchema = z.object({\n channelId: z.string().optional(),\n status: z.nativeEnum(SenderNumberStatus).optional(),\n category: z.nativeEnum(SenderNumberCategory).optional(),\n verified: z.boolean().optional(),\n});\n\nexport type ChannelCreateRequestType = z.infer<typeof ChannelCreateRequestSchema>;\nexport type SenderNumberCreateRequestType = z.infer<typeof SenderNumberCreateRequestSchema>;\nexport type ChannelFiltersType = z.infer<typeof ChannelFiltersSchema>;\nexport type SenderNumberFiltersType = z.infer<typeof SenderNumberFiltersSchema>;\n\n// Additional types for service compatibility\nexport interface ChannelConfig {\n id: string;\n name: string;\n type: 'alimtalk' | 'sms' | 'lms' | 'friendtalk';\n providerId: string;\n active: boolean;\n settings: Record<string, any>;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface ChannelVerificationResult {\n success: boolean;\n status: string;\n verificationCode?: string;\n error?: string;\n}","import { \n Channel, \n ChannelCreateRequest, \n ChannelStatus, \n ChannelType,\n VerificationStatus \n} from '../types/channel.types';\n\nexport class KakaoChannelManager {\n private channels: Map<string, Channel> = new Map();\n\n async createChannel(request: ChannelCreateRequest): Promise<Channel> {\n // Validate Kakao-specific requirements\n this.validateKakaoChannelRequest(request);\n\n const channelId = this.generateChannelId();\n \n const channel: Channel = {\n id: channelId,\n name: request.name,\n provider: request.provider,\n type: request.type,\n status: ChannelStatus.PENDING,\n profileKey: request.profileKey,\n senderNumbers: [],\n metadata: {\n businessInfo: request.businessInfo,\n kakaoInfo: request.kakaoInfo,\n limits: {\n dailyMessageLimit: 10000,\n monthlyMessageLimit: 300000,\n rateLimit: 10 // 10 messages per second\n },\n features: {\n supportsBulkSending: true,\n supportsScheduling: true,\n supportsButtons: true,\n maxButtonCount: 5\n }\n },\n verification: {\n status: request.businessInfo ? VerificationStatus.PENDING : VerificationStatus.NOT_REQUIRED,\n documents: []\n },\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.channels.set(channelId, channel);\n\n // Start verification process if business info is provided\n if (request.businessInfo) {\n await this.initiateBusinessVerification(channel);\n }\n\n return channel;\n }\n\n private validateKakaoChannelRequest(request: ChannelCreateRequest): void {\n if (request.type !== ChannelType.KAKAO_ALIMTALK && request.type !== ChannelType.KAKAO_FRIENDTALK) {\n throw new Error('Invalid channel type for Kakao channel');\n }\n\n if (!request.kakaoInfo?.plusFriendId) {\n throw new Error('Plus Friend ID is required for Kakao channels');\n }\n\n if (!request.kakaoInfo?.brandName) {\n throw new Error('Brand name is required for Kakao channels');\n }\n\n // Validate Plus Friend ID format\n if (!this.isValidPlusFriendId(request.kakaoInfo.plusFriendId)) {\n throw new Error('Invalid Plus Friend ID format');\n }\n }\n\n private isValidPlusFriendId(plusFriendId: string): boolean {\n // Plus Friend ID should start with @ and contain only allowed characters\n const regex = /^@[a-zA-Z0-9_-]{3,30}$/;\n return regex.test(plusFriendId);\n }\n\n private async initiateBusinessVerification(channel: Channel): Promise<void> {\n // In a real implementation, this would integrate with Kakao's verification API\n // For now, we'll simulate the process\n \n channel.verification.status = VerificationStatus.UNDER_REVIEW;\n channel.status = ChannelStatus.VERIFYING;\n channel.updatedAt = new Date();\n\n // Simulate verification process (in real scenario, this would be handled by webhooks)\n setTimeout(() => {\n this.completeVerification(channel.id, true);\n }, 5000); // 5 seconds for demo\n }\n\n async completeVerification(channelId: string, approved: boolean, rejectionReason?: string): Promise<void> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error('Channel not found');\n }\n\n if (approved) {\n channel.verification.status = VerificationStatus.VERIFIED;\n channel.verification.verifiedAt = new Date();\n channel.status = ChannelStatus.ACTIVE;\n } else {\n channel.verification.status = VerificationStatus.REJECTED;\n channel.verification.rejectedAt = new Date();\n channel.verification.rejectionReason = rejectionReason || 'Verification failed';\n channel.status = ChannelStatus.SUSPENDED;\n }\n\n channel.updatedAt = new Date();\n }\n\n async getChannel(channelId: string): Promise<Channel | null> {\n return this.channels.get(channelId) || null;\n }\n\n async updateChannel(channelId: string, updates: Partial<Channel>): Promise<Channel> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error('Channel not found');\n }\n\n // Validate updates\n if (updates.metadata?.kakaoInfo?.plusFriendId && !this.isValidPlusFriendId(updates.metadata.kakaoInfo.plusFriendId)) {\n throw new Error('Invalid Plus Friend ID format');\n }\n\n // Apply updates\n Object.assign(channel, updates, { updatedAt: new Date() });\n\n return channel;\n }\n\n async deleteChannel(channelId: string): Promise<boolean> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n return false;\n }\n\n // Soft delete - mark as deleted instead of removing\n channel.status = ChannelStatus.DELETED;\n channel.updatedAt = new Date();\n\n return true;\n }\n\n async listChannels(filters?: {\n status?: ChannelStatus;\n type?: ChannelType;\n verified?: boolean;\n }): Promise<Channel[]> {\n let channels = Array.from(this.channels.values());\n\n if (filters) {\n if (filters.status) {\n channels = channels.filter(c => c.status === filters.status);\n }\n if (filters.type) {\n channels = channels.filter(c => c.type === filters.type);\n }\n if (filters.verified !== undefined) {\n const verifiedStatus = filters.verified ? VerificationStatus.VERIFIED : VerificationStatus.PENDING;\n channels = channels.filter(c => c.verification.status === verifiedStatus);\n }\n }\n\n // Exclude deleted channels unless specifically requested\n return channels.filter(c => c.status !== ChannelStatus.DELETED);\n }\n\n async suspendChannel(channelId: string, reason: string): Promise<void> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error('Channel not found');\n }\n\n channel.status = ChannelStatus.SUSPENDED;\n channel.updatedAt = new Date();\n \n // Log suspension reason (in real implementation, save to audit log)\n console.log(`Channel ${channelId} suspended: ${reason}`);\n }\n\n async reactivateChannel(channelId: string): Promise<void> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error('Channel not found');\n }\n\n if (channel.verification.status !== VerificationStatus.VERIFIED) {\n throw new Error('Channel must be verified before reactivation');\n }\n\n channel.status = ChannelStatus.ACTIVE;\n channel.updatedAt = new Date();\n }\n\n async checkChannelHealth(channelId: string): Promise<{\n isHealthy: boolean;\n issues: string[];\n recommendations: string[];\n }> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error('Channel not found');\n }\n\n const issues: string[] = [];\n const recommendations: string[] = [];\n\n // Check channel status\n if (channel.status !== ChannelStatus.ACTIVE) {\n issues.push(`Channel status is ${channel.status}`);\n }\n\n // Check verification status\n if (channel.verification.status !== VerificationStatus.VERIFIED && \n channel.verification.status !== VerificationStatus.NOT_REQUIRED) {\n issues.push(`Channel verification is ${channel.verification.status}`);\n }\n\n // Check if channel has sender numbers\n if (channel.senderNumbers.length === 0) {\n recommendations.push('Add at least one verified sender number');\n }\n\n // Check business info completeness\n if (!channel.metadata.businessInfo) {\n recommendations.push('Complete business information for better deliverability');\n }\n\n return {\n isHealthy: issues.length === 0,\n issues,\n recommendations\n };\n }\n\n private generateChannelId(): string {\n return `kakao_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","import { \n SenderNumber, \n SenderNumberCreateRequest, \n SenderNumberStatus, \n SenderNumberCategory \n} from '../types/channel.types';\n\nexport class KakaoSenderNumberManager {\n private senderNumbers: Map<string, SenderNumber> = new Map();\n private verificationCodes: Map<string, { code: string; expiresAt: Date }> = new Map();\n\n async addSenderNumber(\n channelId: string, \n request: SenderNumberCreateRequest\n ): Promise<SenderNumber> {\n // Validate phone number format\n this.validatePhoneNumber(request.phoneNumber);\n\n // Check if number is already registered\n const existingNumber = this.findSenderNumberByPhone(request.phoneNumber);\n if (existingNumber) {\n throw new Error('Phone number is already registered');\n }\n\n const senderNumberId = this.generateSenderNumberId();\n \n const senderNumber: SenderNumber = {\n id: senderNumberId,\n phoneNumber: request.phoneNumber,\n status: SenderNumberStatus.PENDING,\n category: request.category,\n metadata: {\n businessName: request.businessInfo?.businessName,\n businessRegistrationNumber: request.businessInfo?.businessRegistrationNumber,\n contactPerson: request.businessInfo?.contactPerson,\n contactEmail: request.businessInfo?.contactEmail,\n },\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.senderNumbers.set(senderNumberId, senderNumber);\n\n // Initiate verification process\n await this.initiateVerification(senderNumber);\n\n return senderNumber;\n }\n\n private validatePhoneNumber(phoneNumber: string): void {\n // Korean phone number validation\n const regex = /^(010|011|016|017|018|019)[0-9]{7,8}$/;\n if (!regex.test(phoneNumber)) {\n throw new Error('Invalid Korean phone number format');\n }\n }\n\n private findSenderNumberByPhone(phoneNumber: string): SenderNumber | undefined {\n return Array.from(this.senderNumbers.values())\n .find(sn => sn.phoneNumber === phoneNumber);\n }\n\n private async initiateVerification(senderNumber: SenderNumber): Promise<void> {\n // Generate verification code\n const verificationCode = this.generateVerificationCode();\n const expiresAt = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes\n\n // Store verification code\n this.verificationCodes.set(senderNumber.id, {\n code: verificationCode,\n expiresAt\n });\n\n // Update sender number status\n senderNumber.status = SenderNumberStatus.VERIFYING;\n senderNumber.verificationCode = verificationCode;\n senderNumber.updatedAt = new Date();\n\n // In a real implementation, send SMS to the phone number\n console.log(`Verification code for ${senderNumber.phoneNumber}: ${verificationCode}`);\n \n // Simulate SMS sending\n await this.sendVerificationSMS(senderNumber.phoneNumber, verificationCode);\n }\n\n private async sendVerificationSMS(phoneNumber: string, code: string): Promise<void> {\n // In a real implementation, this would use an SMS provider\n console.log(`Sending SMS to ${phoneNumber}: Your verification code is ${code}`);\n }\n\n async verifySenderNumber(senderNumberId: string, code: string): Promise<boolean> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error('Sender number not found');\n }\n\n const verification = this.verificationCodes.get(senderNumberId);\n if (!verification) {\n throw new Error('No verification code found');\n }\n\n // Check if code is expired\n if (new Date() > verification.expiresAt) {\n throw new Error('Verification code has expired');\n }\n\n // Check if code matches\n if (verification.code !== code) {\n return false;\n }\n\n // Mark as verified\n senderNumber.status = SenderNumberStatus.VERIFIED;\n senderNumber.verifiedAt = new Date();\n senderNumber.updatedAt = new Date();\n delete senderNumber.verificationCode;\n\n // Clean up verification code\n this.verificationCodes.delete(senderNumberId);\n\n return true;\n }\n\n async resendVerificationCode(senderNumberId: string): Promise<void> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error('Sender number not found');\n }\n\n if (senderNumber.status !== SenderNumberStatus.VERIFYING) {\n throw new Error('Sender number is not in verifying status');\n }\n\n // Check rate limiting (prevent spam)\n const lastVerification = this.verificationCodes.get(senderNumberId);\n if (lastVerification) {\n const timeSinceLastCode = Date.now() - (lastVerification.expiresAt.getTime() - 5 * 60 * 1000);\n if (timeSinceLastCode < 60 * 1000) { // 1 minute cooldown\n throw new Error('Please wait before requesting a new verification code');\n }\n }\n\n // Generate new verification code\n await this.initiateVerification(senderNumber);\n }\n\n async getSenderNumber(senderNumberId: string): Promise<SenderNumber | null> {\n return this.senderNumbers.get(senderNumberId) || null;\n }\n\n async listSenderNumbers(filters?: {\n channelId?: string;\n status?: SenderNumberStatus;\n category?: SenderNumberCategory;\n verified?: boolean;\n }): Promise<SenderNumber[]> {\n let senderNumbers = Array.from(this.senderNumbers.values());\n\n if (filters) {\n if (filters.status) {\n senderNumbers = senderNumbers.filter(sn => sn.status === filters.status);\n }\n if (filters.category) {\n senderNumbers = senderNumbers.filter(sn => sn.category === filters.category);\n }\n if (filters.verified !== undefined) {\n if (filters.verified) {\n senderNumbers = senderNumbers.filter(sn => sn.status === SenderNumberStatus.VERIFIED);\n } else {\n senderNumbers = senderNumbers.filter(sn => sn.status !== SenderNumberStatus.VERIFIED);\n }\n }\n }\n\n return senderNumbers;\n }\n\n async updateSenderNumber(\n senderNumberId: string, \n updates: Partial<SenderNumber>\n ): Promise<SenderNumber> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error('Sender number not found');\n }\n\n // Prevent updating certain fields\n const allowedUpdates = { ...updates };\n delete allowedUpdates.id;\n delete allowedUpdates.phoneNumber;\n delete allowedUpdates.verifiedAt;\n delete allowedUpdates.createdAt;\n\n Object.assign(senderNumber, allowedUpdates, { updatedAt: new Date() });\n\n return senderNumber;\n }\n\n async deleteSenderNumber(senderNumberId: string): Promise<boolean> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n return false;\n }\n\n // Check if sender number is being used\n if (await this.isSenderNumberInUse(senderNumberId)) {\n throw new Error('Cannot delete sender number that is currently in use');\n }\n\n this.senderNumbers.delete(senderNumberId);\n this.verificationCodes.delete(senderNumberId);\n\n return true;\n }\n\n private async isSenderNumberInUse(senderNumberId: string): Promise<boolean> {\n // In a real implementation, check if any templates or active campaigns use this sender number\n return false;\n }\n\n async blockSenderNumber(senderNumberId: string, reason: string): Promise<void> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error('Sender number not found');\n }\n\n senderNumber.status = SenderNumberStatus.BLOCKED;\n senderNumber.updatedAt = new Date();\n\n // Log blocking reason (in real implementation, save to audit log)\n console.log(`Sender number ${senderNumberId} blocked: ${reason}`);\n }\n\n async unblockSenderNumber(senderNumberId: string): Promise<void> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error('Sender number not found');\n }\n\n if (senderNumber.status !== SenderNumberStatus.BLOCKED) {\n throw new Error('Sender number is not blocked');\n }\n\n // Restore to previous status (assume verified if was blocked)\n senderNumber.status = senderNumber.verifiedAt ? \n SenderNumberStatus.VERIFIED : \n SenderNumberStatus.PENDING;\n senderNumber.updatedAt = new Date();\n }\n\n async validateSenderNumberForSending(senderNumberId: string): Promise<{\n isValid: boolean;\n errors: string[];\n }> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n const errors: string[] = [];\n\n if (!senderNumber) {\n errors.push('Sender number not found');\n return { isValid: false, errors };\n }\n\n if (senderNumber.status !== SenderNumberStatus.VERIFIED) {\n errors.push(`Sender number status is ${senderNumber.status}, must be verified`);\n }\n\n if (!senderNumber.verifiedAt) {\n errors.push('Sender number has not been verified');\n }\n\n // Check if verification is recent (within 1 year)\n if (senderNumber.verifiedAt) {\n const oneYearAgo = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000);\n if (senderNumber.verifiedAt < oneYearAgo) {\n errors.push('Sender number verification has expired');\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n private generateSenderNumberId(): string {\n return `sn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private generateVerificationCode(): string {\n return Math.floor(100000 + Math.random() * 900000).toString();\n }\n\n // Cleanup expired verification codes\n cleanup(): void {\n const now = new Date();\n for (const [id, verification] of this.verificationCodes) {\n if (now > verification.expiresAt) {\n this.verificationCodes.delete(id);\n \n // Reset sender number status if verification expired\n const senderNumber = this.senderNumbers.get(id);\n if (senderNumber && senderNumber.status === SenderNumberStatus.VERIFYING) {\n senderNumber.status = SenderNumberStatus.PENDING;\n delete senderNumber.verificationCode;\n senderNumber.updatedAt = new Date();\n }\n }\n }\n }\n}","/**\n * Channel CRUD Operations\n * 채널 생성, 조회, 수정, 삭제 통합 관리\n */\n\nimport { EventEmitter } from 'events';\nimport {\n Channel,\n SenderNumber,\n ChannelCreateRequest,\n SenderNumberCreateRequest,\n ChannelFilters,\n SenderNumberFilters,\n ChannelStatus,\n SenderNumberStatus,\n ChannelType,\n VerificationStatus\n} from '../types/channel.types';\n\nexport interface PaginationOptions {\n page: number;\n limit: number;\n sortBy?: string;\n sortOrder?: 'asc' | 'desc';\n}\n\nexport interface PaginatedResult<T> {\n data: T[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n}\n\nexport interface ChannelCRUDOptions {\n enableAuditLog: boolean;\n enableEventEmission: boolean;\n defaultPageSize: number;\n maxPageSize: number;\n enableSoftDelete: boolean;\n autoCleanup: boolean;\n cleanupInterval: number; // in milliseconds\n}\n\nexport interface AuditLogEntry {\n id: string;\n entityType: 'channel' | 'senderNumber';\n entityId: string;\n action: 'create' | 'read' | 'update' | 'delete' | 'verify' | 'suspend' | 'activate';\n userId?: string;\n timestamp: Date;\n changes?: {\n before: any;\n after: any;\n };\n metadata?: Record<string, any>;\n}\n\nexport class ChannelCRUD extends EventEmitter {\n private channels = new Map<string, Channel>();\n private senderNumbers = new Map<string, SenderNumber>();\n private auditLogs: AuditLogEntry[] = [];\n private cleanupTimer?: NodeJS.Timeout;\n\n private defaultOptions: ChannelCRUDOptions = {\n enableAuditLog: true,\n enableEventEmission: true,\n defaultPageSize: 20,\n maxPageSize: 100,\n enableSoftDelete: true,\n autoCleanup: true,\n cleanupInterval: 3600000 // 1 hour\n };\n\n constructor(private options: Partial<ChannelCRUDOptions> = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n\n if (this.options.autoCleanup) {\n this.startAutoCleanup();\n }\n }\n\n // Channel CRUD Operations\n async createChannel(request: ChannelCreateRequest, userId?: string): Promise<Channel> {\n const channelId = this.generateChannelId();\n \n const channel: Channel = {\n id: channelId,\n name: request.name,\n provider: request.provider,\n type: request.type,\n status: ChannelStatus.PENDING,\n profileKey: request.profileKey,\n senderNumbers: [],\n metadata: {\n businessInfo: request.businessInfo,\n kakaoInfo: request.kakaoInfo,\n limits: this.getDefaultLimits(request.type),\n features: this.getDefaultFeatures(request.type)\n },\n verification: {\n status: request.businessInfo ? VerificationStatus.PENDING : VerificationStatus.NOT_REQUIRED,\n documents: []\n },\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.channels.set(channelId, channel);\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('channel', channelId, 'create', userId, undefined, channel);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('channel:created', { channel, userId });\n }\n\n return channel;\n }\n\n async getChannel(channelId: string, userId?: string): Promise<Channel | null> {\n const channel = this.channels.get(channelId);\n \n if (channel && this.options.enableAuditLog) {\n this.addAuditLog('channel', channelId, 'read', userId);\n }\n\n return channel || null;\n }\n\n async updateChannel(\n channelId: string, \n updates: Partial<Omit<Channel, 'id' | 'createdAt' | 'updatedAt'>>,\n userId?: string\n ): Promise<Channel> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error(`Channel ${channelId} not found`);\n }\n\n const before = this.options.enableAuditLog ? { ...channel } : undefined;\n \n // Apply updates\n const updatedChannel = {\n ...channel,\n ...updates,\n id: channelId, // Ensure ID doesn't change\n updatedAt: new Date()\n };\n\n this.channels.set(channelId, updatedChannel);\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('channel', channelId, 'update', userId, before, updatedChannel);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('channel:updated', { \n channel: updatedChannel, \n previousChannel: channel,\n userId \n });\n }\n\n return updatedChannel;\n }\n\n async deleteChannel(channelId: string, userId?: string): Promise<boolean> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n return false;\n }\n\n if (this.options.enableSoftDelete) {\n // Soft delete - mark as deleted\n channel.status = ChannelStatus.DELETED;\n channel.updatedAt = new Date();\n } else {\n // Hard delete - remove from memory\n this.channels.delete(channelId);\n \n // Also delete associated sender numbers\n for (const [id, senderNumber] of this.senderNumbers) {\n // In a real implementation, we'd have a channelId field in SenderNumber\n // For now, we'll skip this cleanup\n }\n }\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('channel', channelId, 'delete', userId, channel);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('channel:deleted', { channel, userId });\n }\n\n return true;\n }\n\n async listChannels(\n filters: ChannelFilters = {}, \n pagination: PaginationOptions = { page: 1, limit: this.options.defaultPageSize! }\n ): Promise<PaginatedResult<Channel>> {\n let channels = Array.from(this.channels.values());\n\n // Apply filters\n if (filters.provider) {\n channels = channels.filter(c => c.provider === filters.provider);\n }\n if (filters.type) {\n channels = channels.filter(c => c.type === filters.type);\n }\n if (filters.status) {\n channels = channels.filter(c => c.status === filters.status);\n }\n if (filters.verified !== undefined) {\n const targetStatus = filters.verified ? VerificationStatus.VERIFIED : VerificationStatus.PENDING;\n channels = channels.filter(c => c.verification.status === targetStatus);\n }\n if (filters.createdAfter) {\n channels = channels.filter(c => c.createdAt >= filters.createdAfter!);\n }\n if (filters.createdBefore) {\n channels = channels.filter(c => c.createdAt <= filters.createdBefore!);\n }\n\n // Exclude soft deleted channels unless specifically requested\n if (!filters.status || filters.status !== ChannelStatus.DELETED) {\n channels = channels.filter(c => c.status !== ChannelStatus.DELETED);\n }\n\n // Apply sorting\n const sortBy = pagination.sortBy || 'createdAt';\n const sortOrder = pagination.sortOrder || 'desc';\n \n channels.sort((a, b) => {\n let aValue: any, bValue: any;\n \n switch (sortBy) {\n case 'name':\n aValue = a.name;\n bValue = b.name;\n break;\n case 'createdAt':\n aValue = a.createdAt.getTime();\n bValue = b.createdAt.getTime();\n break;\n case 'updatedAt':\n aValue = a.updatedAt.getTime();\n bValue = b.updatedAt.getTime();\n break;\n default:\n aValue = a.createdAt.getTime();\n bValue = b.createdAt.getTime();\n }\n\n if (sortOrder === 'asc') {\n return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;\n } else {\n return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;\n }\n });\n\n // Apply pagination\n const total = channels.length;\n const limit = Math.min(pagination.limit, this.options.maxPageSize!);\n const page = Math.max(1, pagination.page);\n const offset = (page - 1) * limit;\n const paginatedChannels = channels.slice(offset, offset + limit);\n\n return {\n data: paginatedChannels,\n total,\n page,\n limit,\n totalPages: Math.ceil(total / limit),\n hasNext: offset + limit < total,\n hasPrev: page > 1\n };\n }\n\n // Sender Number CRUD Operations\n async createSenderNumber(\n channelId: string,\n request: SenderNumberCreateRequest,\n userId?: string\n ): Promise<SenderNumber> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error(`Channel ${channelId} not found`);\n }\n\n const senderNumberId = this.generateSenderNumberId();\n \n const senderNumber: SenderNumber = {\n id: senderNumberId,\n phoneNumber: request.phoneNumber,\n status: SenderNumberStatus.PENDING,\n category: request.category,\n metadata: {\n businessName: request.businessInfo?.businessName,\n businessRegistrationNumber: request.businessInfo?.businessRegistrationNumber,\n contactPerson: request.businessInfo?.contactPerson,\n contactEmail: request.businessInfo?.contactEmail,\n },\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.senderNumbers.set(senderNumberId, senderNumber);\n\n // Add to channel's sender numbers\n channel.senderNumbers.push(senderNumber);\n channel.updatedAt = new Date();\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('senderNumber', senderNumberId, 'create', userId, undefined, senderNumber);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('senderNumber:created', { senderNumber, channelId, userId });\n }\n\n return senderNumber;\n }\n\n async getSenderNumber(senderNumberId: string, userId?: string): Promise<SenderNumber | null> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n \n if (senderNumber && this.options.enableAuditLog) {\n this.addAuditLog('senderNumber', senderNumberId, 'read', userId);\n }\n\n return senderNumber || null;\n }\n\n async updateSenderNumber(\n senderNumberId: string,\n updates: Partial<Omit<SenderNumber, 'id' | 'phoneNumber' | 'createdAt' | 'updatedAt'>>,\n userId?: string\n ): Promise<SenderNumber> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n throw new Error(`Sender number ${senderNumberId} not found`);\n }\n\n const before = this.options.enableAuditLog ? { ...senderNumber } : undefined;\n \n // Apply updates\n const updatedSenderNumber = {\n ...senderNumber,\n ...updates,\n id: senderNumberId, // Ensure ID doesn't change\n updatedAt: new Date()\n };\n\n this.senderNumbers.set(senderNumberId, updatedSenderNumber);\n\n // Update in channel's sender numbers array\n for (const channel of this.channels.values()) {\n const index = channel.senderNumbers.findIndex(sn => sn.id === senderNumberId);\n if (index !== -1) {\n channel.senderNumbers[index] = updatedSenderNumber;\n channel.updatedAt = new Date();\n break;\n }\n }\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('senderNumber', senderNumberId, 'update', userId, before, updatedSenderNumber);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('senderNumber:updated', { \n senderNumber: updatedSenderNumber, \n previousSenderNumber: senderNumber,\n userId \n });\n }\n\n return updatedSenderNumber;\n }\n\n async deleteSenderNumber(senderNumberId: string, userId?: string): Promise<boolean> {\n const senderNumber = this.senderNumbers.get(senderNumberId);\n if (!senderNumber) {\n return false;\n }\n\n // Remove from memory\n this.senderNumbers.delete(senderNumberId);\n\n // Remove from channel's sender numbers array\n for (const channel of this.channels.values()) {\n const index = channel.senderNumbers.findIndex(sn => sn.id === senderNumberId);\n if (index !== -1) {\n channel.senderNumbers.splice(index, 1);\n channel.updatedAt = new Date();\n break;\n }\n }\n\n // Audit log\n if (this.options.enableAuditLog) {\n this.addAuditLog('senderNumber', senderNumberId, 'delete', userId, senderNumber);\n }\n\n // Event emission\n if (this.options.enableEventEmission) {\n this.emit('senderNumber:deleted', { senderNumber, userId });\n }\n\n return true;\n }\n\n async listSenderNumbers(\n filters: SenderNumberFilters = {},\n pagination: PaginationOptions = { page: 1, limit: this.options.defaultPageSize! }\n ): Promise<PaginatedResult<SenderNumber>> {\n let senderNumbers = Array.from(this.senderNumbers.values());\n\n // Apply filters\n if (filters.channelId) {\n const channel = this.channels.get(filters.channelId);\n if (channel) {\n senderNumbers = channel.senderNumbers;\n } else {\n senderNumbers = [];\n }\n }\n if (filters.status) {\n senderNumbers = senderNumbers.filter(sn => sn.status === filters.status);\n }\n if (filters.category) {\n senderNumbers = senderNumbers.filter(sn => sn.category === filters.category);\n }\n if (filters.verified !== undefined) {\n if (filters.verified) {\n senderNumbers = senderNumbers.filter(sn => sn.status === SenderNumberStatus.VERIFIED);\n } else {\n senderNumbers = senderNumbers.filter(sn => sn.status !== SenderNumberStatus.VERIFIED);\n }\n }\n\n // Apply sorting\n const sortBy = pagination.sortBy || 'createdAt';\n const sortOrder = pagination.sortOrder || 'desc';\n \n senderNumbers.sort((a, b) => {\n let aValue: any, bValue: any;\n \n switch (sortBy) {\n case 'phoneNumber':\n aValue = a.phoneNumber;\n bValue = b.phoneNumber;\n break;\n case 'createdAt':\n aValue = a.createdAt.getTime();\n bValue = b.createdAt.getTime();\n break;\n case 'updatedAt':\n aValue = a.updatedAt.getTime();\n bValue = b.updatedAt.getTime();\n break;\n default:\n aValue = a.createdAt.getTime();\n bValue = b.createdAt.getTime();\n }\n\n if (sortOrder === 'asc') {\n return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;\n } else {\n return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;\n }\n });\n\n // Apply pagination\n const total = senderNumbers.length;\n const limit = Math.min(pagination.limit, this.options.maxPageSize!);\n const page = Math.max(1, pagination.page);\n const offset = (page - 1) * limit;\n const paginatedSenderNumbers = senderNumbers.slice(offset, offset + limit);\n\n return {\n data: paginatedSenderNumbers,\n total,\n page,\n limit,\n totalPages: Math.ceil(total / limit),\n hasNext: offset + limit < total,\n hasPrev: page > 1\n };\n }\n\n // Audit and Analytics\n getAuditLogs(\n entityType?: 'channel' | 'senderNumber',\n entityId?: string,\n limit: number = 100\n ): AuditLogEntry[] {\n let logs = [...this.auditLogs];\n\n if (entityType) {\n logs = logs.filter(log => log.entityType === entityType);\n }\n if (entityId) {\n logs = logs.filter(log => log.entityId === entityId);\n }\n\n return logs\n .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())\n .slice(0, limit);\n }\n\n getStatistics(): {\n channels: {\n total: number;\n byStatus: Record<string, number>;\n byType: Record<string, number>;\n byProvider: Record<string, number>;\n };\n senderNumbers: {\n total: number;\n byStatus: Record<string, number>;\n byCategory: Record<string, number>;\n };\n } {\n const channels = Array.from(this.channels.values());\n const senderNumbers = Array.from(this.senderNumbers.values());\n\n const channelsByStatus: Record<string, number> = {};\n const channelsByType: Record<string, number> = {};\n const channelsByProvider: Record<string, number> = {};\n\n channels.forEach(channel => {\n channelsByStatus[channel.status] = (channelsByStatus[channel.status] || 0) + 1;\n channelsByType[channel.type] = (channelsByType[channel.type] || 0) + 1;\n channelsByProvider[channel.provider] = (channelsByProvider[channel.provider] || 0) + 1;\n });\n\n const senderNumbersByStatus: Record<string, number> = {};\n const senderNumbersByCategory: Record<string, number> = {};\n\n senderNumbers.forEach(senderNumber => {\n senderNumbersByStatus[senderNumber.status] = (senderNumbersByStatus[senderNumber.status] || 0) + 1;\n senderNumbersByCategory[senderNumber.category] = (senderNumbersByCategory[senderNumber.category] || 0) + 1;\n });\n\n return {\n channels: {\n total: channels.length,\n byStatus: channelsByStatus,\n byType: channelsByType,\n byProvider: channelsByProvider\n },\n senderNumbers: {\n total: senderNumbers.length,\n byStatus: senderNumbersByStatus,\n byCategory: senderNumbersByCategory\n }\n };\n }\n\n // Cleanup and Maintenance\n cleanup(): {\n deletedChannels: number;\n expiredAuditLogs: number;\n } {\n let deletedChannels = 0;\n let expiredAuditLogs = 0;\n\n // Clean up soft-deleted channels older than 30 days\n const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n \n for (const [id, channel] of this.channels) {\n if (channel.status === ChannelStatus.DELETED && channel.updatedAt < thirtyDaysAgo) {\n this.channels.delete(id);\n deletedChannels++;\n }\n }\n\n // Clean up audit logs older than 90 days\n const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);\n const originalLogCount = this.auditLogs.length;\n this.auditLogs = this.auditLogs.filter(log => log.timestamp >= ninetyDaysAgo);\n expiredAuditLogs = originalLogCount - this.auditLogs.length;\n\n return { deletedChannels, expiredAuditLogs };\n }\n\n destroy(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n \n this.removeAllListeners();\n this.channels.clear();\n this.senderNumbers.clear();\n this.auditLogs = [];\n }\n\n private addAuditLog(\n entityType: 'channel' | 'senderNumber',\n entityId: string,\n action: AuditLogEntry['action'],\n userId?: string,\n before?: any,\n after?: any\n ): void {\n const auditLog: AuditLogEntry = {\n id: this.generateAuditLogId(),\n entityType,\n entityId,\n action,\n userId,\n timestamp: new Date(),\n changes: before || after ? { before, after } : undefined\n };\n\n this.auditLogs.push(auditLog);\n\n // Keep only last 10000 audit logs to prevent memory issues\n if (this.auditLogs.length > 10000) {\n this.auditLogs = this.auditLogs.slice(-10000);\n }\n }\n\n private getDefaultLimits(channelType: ChannelType) {\n switch (channelType) {\n case ChannelType.KAKAO_ALIMTALK:\n return {\n dailyMessageLimit: 10000,\n monthlyMessageLimit: 300000,\n rateLimit: 10\n };\n case ChannelType.KAKAO_FRIENDTALK:\n return {\n dailyMessageLimit: 1000,\n monthlyMessageLimit: 30000,\n rateLimit: 5\n };\n case ChannelType.SMS:\n case ChannelType.LMS:\n case ChannelType.MMS:\n return {\n dailyMessageLimit: 1000,\n monthlyMessageLimit: 30000,\n rateLimit: 3\n };\n default:\n return {\n dailyMessageLimit: 1000,\n monthlyMessageLimit: 30000,\n rateLimit: 1\n };\n }\n }\n\n private getDefaultFeatures(channelType: ChannelType) {\n switch (channelType) {\n case ChannelType.KAKAO_ALIMTALK:\n return {\n supportsBulkSending: true,\n supportsScheduling: true,\n supportsButtons: true,\n maxButtonCount: 5\n };\n case ChannelType.KAKAO_FRIENDTALK:\n return {\n supportsBulkSending: true,\n supportsScheduling: true,\n supportsButtons: false,\n maxButtonCount: 0\n };\n default:\n return {\n supportsBulkSending: false,\n supportsScheduling: false,\n supportsButtons: false,\n maxButtonCount: 0\n };\n }\n }\n\n private startAutoCleanup(): void {\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, this.options.cleanupInterval!);\n }\n\n private generateChannelId(): string {\n return `ch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private generateSenderNumberId(): string {\n return `sn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private generateAuditLogId(): string {\n return `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","/**\n * Permission Management System\n * 채널 및 발신번호 액세스 권한 관리\n */\n\nimport { EventEmitter } from 'events';\n\nexport interface User {\n id: string;\n email: string;\n name: string;\n roles: Role[];\n isActive: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface Role {\n id: string;\n name: string;\n permissions: Permission[];\n description?: string;\n isSystem: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface Permission {\n id: string;\n resource: ResourceType;\n action: ActionType;\n scope: PermissionScope;\n conditions?: PermissionCondition[];\n}\n\nexport enum ResourceType {\n CHANNEL = 'channel',\n SENDER_NUMBER = 'senderNumber',\n TEMPLATE = 'template',\n MESSAGE = 'message',\n USER = 'user',\n ROLE = 'role',\n AUDIT_LOG = 'auditLog',\n ANALYTICS = 'analytics'\n}\n\nexport enum ActionType {\n CREATE = 'create',\n READ = 'read',\n UPDATE = 'update',\n DELETE = 'delete',\n VERIFY = 'verify',\n SUSPEND = 'suspend',\n ACTIVATE = 'activate',\n SEND = 'send',\n MANAGE = 'manage'\n}\n\nexport enum PermissionScope {\n GLOBAL = 'global',\n ORGANIZATION = 'organization',\n TEAM = 'team',\n PERSONAL = 'personal'\n}\n\nexport interface PermissionCondition {\n field: string;\n operator: 'equals' | 'not_equals' | 'in' | 'not_in' | 'contains' | 'starts_with';\n value: any;\n}\n\nexport interface AccessContext {\n userId: string;\n organizationId?: string;\n teamId?: string;\n resourceOwnerId?: string;\n metadata?: Record<string, any>;\n}\n\nexport interface PermissionCheck {\n userId: string;\n resource: ResourceType;\n action: ActionType;\n resourceId?: string;\n context?: AccessContext;\n}\n\nexport interface PermissionResult {\n granted: boolean;\n reason?: string;\n matchedPermissions: Permission[];\n deniedReasons: string[];\n}\n\nexport class PermissionManager extends EventEmitter {\n private users = new Map<string, User>();\n private roles = new Map<string, Role>();\n private userRoleCache = new Map<string, Set<string>>();\n private permissionCache = new Map<string, PermissionResult>();\n private cacheExpiry = new Map<string, number>();\n\n private readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes\n\n constructor() {\n super();\n this.initializeSystemRoles();\n }\n\n // User Management\n async createUser(userData: Omit<User, 'id' | 'createdAt' | 'updatedAt'>): Promise<User> {\n const userId = this.generateUserId();\n \n const user: User = {\n ...userData,\n id: userId,\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.users.set(userId, user);\n this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n\n this.emit('user:created', { user });\n return user;\n }\n\n async getUser(userId: string): Promise<User | null> {\n return this.users.get(userId) || null;\n }\n\n async updateUser(userId: string, updates: Partial<User>): Promise<User> {\n const user = this.users.get(userId);\n if (!user) {\n throw new Error('User not found');\n }\n\n const updatedUser = {\n ...user,\n ...updates,\n id: userId,\n updatedAt: new Date()\n };\n\n this.users.set(userId, updatedUser);\n\n // Update role cache if roles changed\n if (updates.roles) {\n this.updateUserRoleCache(userId, updates.roles.map(r => r.id));\n }\n\n // Clear permission cache for this user\n this.clearUserPermissionCache(userId);\n\n this.emit('user:updated', { user: updatedUser, previousUser: user });\n return updatedUser;\n }\n\n async deleteUser(userId: string): Promise<boolean> {\n const user = this.users.get(userId);\n if (!user) {\n return false;\n }\n\n this.users.delete(userId);\n this.userRoleCache.delete(userId);\n this.clearUserPermissionCache(userId);\n\n this.emit('user:deleted', { user });\n return true;\n }\n\n // Role Management\n async createRole(roleData: Omit<Role, 'id' | 'createdAt' | 'updatedAt'>): Promise<Role> {\n const roleId = this.generateRoleId();\n \n const role: Role = {\n ...roleData,\n id: roleId,\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.roles.set(roleId, role);\n\n this.emit('role:created', { role });\n return role;\n }\n\n async getRole(roleId: string): Promise<Role | null> {\n return this.roles.get(roleId) || null;\n }\n\n async updateRole(roleId: string, updates: Partial<Role>): Promise<Role> {\n const role = this.roles.get(roleId);\n if (!role) {\n throw new Error('Role not found');\n }\n\n if (role.isSystem && updates.permissions) {\n throw new Error('Cannot modify permissions of system roles');\n }\n\n const updatedRole = {\n ...role,\n ...updates,\n id: roleId,\n updatedAt: new Date()\n };\n\n this.roles.set(roleId, updatedRole);\n\n // Clear permission cache for all users with this role\n this.clearRolePermissionCache(roleId);\n\n this.emit('role:updated', { role: updatedRole, previousRole: role });\n return updatedRole;\n }\n\n async deleteRole(roleId: string): Promise<boolean> {\n const role = this.roles.get(roleId);\n if (!role) {\n return false;\n }\n\n if (role.isSystem) {\n throw new Error('Cannot delete system roles');\n }\n\n // Check if role is assigned to any users\n const usersWithRole = Array.from(this.users.values())\n .filter(user => user.roles.some(r => r.id === roleId));\n\n if (usersWithRole.length > 0) {\n throw new Error('Cannot delete role that is assigned to users');\n }\n\n this.roles.delete(roleId);\n\n this.emit('role:deleted', { role });\n return true;\n }\n\n // Permission Management\n async assignRoleToUser(userId: string, roleId: string): Promise<void> {\n const user = this.users.get(userId);\n const role = this.roles.get(roleId);\n\n if (!user) {\n throw new Error('User not found');\n }\n if (!role) {\n throw new Error('Role not found');\n }\n\n // Check if role is already assigned\n if (user.roles.some(r => r.id === roleId)) {\n return;\n }\n\n user.roles.push(role);\n user.updatedAt = new Date();\n\n this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n this.clearUserPermissionCache(userId);\n\n this.emit('role:assigned', { userId, roleId });\n }\n\n async removeRoleFromUser(userId: string, roleId: string): Promise<void> {\n const user = this.users.get(userId);\n if (!user) {\n throw new Error('User not found');\n }\n\n const roleIndex = user.roles.findIndex(r => r.id === roleId);\n if (roleIndex === -1) {\n return;\n }\n\n user.roles.splice(roleIndex, 1);\n user.updatedAt = new Date();\n\n this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n this.clearUserPermissionCache(userId);\n\n this.emit('role:removed', { userId, roleId });\n }\n\n // Permission Checking\n async checkPermission(check: PermissionCheck): Promise<PermissionResult> {\n // Check cache first\n const cacheKey = this.getCacheKey(check);\n const cached = this.getFromCache(cacheKey);\n if (cached) {\n return cached;\n }\n\n const result = await this.performPermissionCheck(check);\n\n // Cache the result\n this.setCache(cacheKey, result);\n\n return result;\n }\n\n async hasPermission(\n userId: string,\n resource: ResourceType,\n action: ActionType,\n resourceId?: string,\n context?: AccessContext\n ): Promise<boolean> {\n const result = await this.checkPermission({\n userId,\n resource,\n action,\n resourceId,\n context\n });\n\n return result.granted;\n }\n\n async requirePermission(\n userId: string,\n resource: ResourceType,\n action: ActionType,\n resourceId?: string,\n context?: AccessContext\n ): Promise<void> {\n const hasAccess = await this.hasPermission(userId, resource, action, resourceId, context);\n \n if (!hasAccess) {\n throw new Error(`Access denied: ${action} on ${resource}`);\n }\n }\n\n // Utility Methods\n async getUserPermissions(userId: string): Promise<Permission[]> {\n const user = this.users.get(userId);\n if (!user) {\n return [];\n }\n\n const permissions: Permission[] = [];\n \n for (const role of user.roles) {\n permissions.push(...role.permissions);\n }\n\n // Remove duplicates\n const uniquePermissions = permissions.filter((permission, index, self) =>\n index === self.findIndex(p => p.id === permission.id)\n );\n\n return uniquePermissions;\n }\n\n async getUserRoles(userId: string): Promise<Role[]> {\n const user = this.users.get(userId);\n return user ? user.roles : [];\n }\n\n listUsers(filters?: {\n isActive?: boolean;\n roleId?: string;\n }): User[] {\n let users = Array.from(this.users.values());\n\n if (filters?.isActive !== undefined) {\n users = users.filter(u => u.isActive === filters.isActive);\n }\n\n if (filters?.roleId) {\n users = users.filter(u => u.roles.some(r => r.id === filters.roleId));\n }\n\n return users;\n }\n\n listRoles(): Role[] {\n return Array.from(this.roles.values());\n }\n\n // Private Methods\n private async performPermissionCheck(check: PermissionCheck): Promise<PermissionResult> {\n const user = this.users.get(check.userId);\n if (!user) {\n return {\n granted: false,\n reason: 'User not found',\n matchedPermissions: [],\n deniedReasons: ['User not found']\n };\n }\n\n if (!user.isActive) {\n return {\n granted: false,\n reason: 'User is inactive',\n matchedPermissions: [],\n deniedReasons: ['User is inactive']\n };\n }\n\n const matchedPermissions: Permission[] = [];\n const deniedReasons: string[] = [];\n\n // Check all user's roles\n for (const role of user.roles) {\n for (const permission of role.permissions) {\n if (this.doesPermissionMatch(permission, check)) {\n // Check conditions\n if (await this.checkConditions(permission, check)) {\n matchedPermissions.push(permission);\n } else {\n deniedReasons.push(`Conditions not met for permission ${permission.id}`);\n }\n }\n }\n }\n\n const granted = matchedPermissions.length > 0;\n\n return {\n granted,\n reason: granted ? undefined : 'No matching permissions found',\n matchedPermissions,\n deniedReasons: granted ? [] : deniedReasons\n };\n }\n\n private doesPermissionMatch(permission: Permission, check: PermissionCheck): boolean {\n return permission.resource === check.resource && permission.action === check.action;\n }\n\n private async checkConditions(permission: Permission, check: PermissionCheck): Promise<boolean> {\n if (!permission.conditions || permission.conditions.length === 0) {\n return true;\n }\n\n // For simplicity, all conditions must be met (AND logic)\n for (const condition of permission.conditions) {\n if (!await this.evaluateCondition(condition, check)) {\n return false;\n }\n }\n\n return true;\n }\n\n private async evaluateCondition(condition: PermissionCondition, check: PermissionCheck): Promise<boolean> {\n let actualValue: any;\n\n // Get the actual value based on the field\n switch (condition.field) {\n case 'userId':\n actualValue = check.userId;\n break;\n case 'organizationId':\n actualValue = check.context?.organizationId;\n break;\n case 'teamId':\n actualValue = check.context?.teamId;\n break;\n case 'resourceOwnerId':\n actualValue = check.context?.resourceOwnerId;\n break;\n default:\n actualValue = check.context?.metadata?.[condition.field];\n }\n\n // Evaluate the condition\n switch (condition.operator) {\n case 'equals':\n return actualValue === condition.value;\n case 'not_equals':\n return actualValue !== condition.value;\n case 'in':\n return Array.isArray(condition.value) && condition.value.includes(actualValue);\n case 'not_in':\n return Array.isArray(condition.value) && !condition.value.includes(actualValue);\n case 'contains':\n return String(actualValue).includes(String(condition.value));\n case 'starts_with':\n return String(actualValue).startsWith(String(condition.value));\n default:\n return false;\n }\n }\n\n private initializeSystemRoles(): void {\n // Super Admin Role\n const superAdminRole: Role = {\n id: 'super-admin',\n name: 'Super Admin',\n description: 'Full system access',\n isSystem: true,\n permissions: [\n // Global permissions for all resources and actions\n ...Object.values(ResourceType).flatMap(resource =>\n Object.values(ActionType).map(action => ({\n id: `super-admin-${resource}-${action}`,\n resource,\n action,\n scope: PermissionScope.GLOBAL\n }))\n )\n ],\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n // Channel Admin Role\n const channelAdminRole: Role = {\n id: 'channel-admin',\n name: 'Channel Admin',\n description: 'Manage channels and sender numbers',\n isSystem: true,\n permissions: [\n {\n id: 'channel-admin-channel-manage',\n resource: ResourceType.CHANNEL,\n action: ActionType.MANAGE,\n scope: PermissionScope.ORGANIZATION\n },\n {\n id: 'channel-admin-sender-manage',\n resource: ResourceType.SENDER_NUMBER,\n action: ActionType.MANAGE,\n scope: PermissionScope.ORGANIZATION\n }\n ],\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n // Message Sender Role\n const messageSenderRole: Role = {\n id: 'message-sender',\n name: 'Message Sender',\n description: 'Send messages using configured channels',\n isSystem: true,\n permissions: [\n {\n id: 'message-sender-channel-read',\n resource: ResourceType.CHANNEL,\n action: ActionType.READ,\n scope: PermissionScope.ORGANIZATION\n },\n {\n id: 'message-sender-message-send',\n resource: ResourceType.MESSAGE,\n action: ActionType.SEND,\n scope: PermissionScope.ORGANIZATION\n }\n ],\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n // Viewer Role\n const viewerRole: Role = {\n id: 'viewer',\n name: 'Viewer',\n description: 'Read-only access',\n isSystem: true,\n permissions: [\n {\n id: 'viewer-channel-read',\n resource: ResourceType.CHANNEL,\n action: ActionType.READ,\n scope: PermissionScope.ORGANIZATION\n },\n {\n id: 'viewer-sender-read',\n resource: ResourceType.SENDER_NUMBER,\n action: ActionType.READ,\n scope: PermissionScope.ORGANIZATION\n },\n {\n id: 'viewer-analytics-read',\n resource: ResourceType.ANALYTICS,\n action: ActionType.READ,\n scope: PermissionScope.ORGANIZATION\n }\n ],\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.roles.set(superAdminRole.id, superAdminRole);\n this.roles.set(channelAdminRole.id, channelAdminRole);\n this.roles.set(messageSenderRole.id, messageSenderRole);\n this.roles.set(viewerRole.id, viewerRole);\n }\n\n private updateUserRoleCache(userId: string, roleIds: string[]): void {\n this.userRoleCache.set(userId, new Set(roleIds));\n }\n\n private clearUserPermissionCache(userId: string): void {\n const keysToDelete: string[] = [];\n \n for (const key of this.permissionCache.keys()) {\n if (key.startsWith(`${userId}:`)) {\n keysToDelete.push(key);\n }\n }\n\n keysToDelete.forEach(key => {\n this.permissionCache.delete(key);\n this.cacheExpiry.delete(key);\n });\n }\n\n private clearRolePermissionCache(roleId: string): void {\n // Find all users with this role and clear their cache\n for (const [userId, roleIds] of this.userRoleCache) {\n if (roleIds.has(roleId)) {\n this.clearUserPermissionCache(userId);\n }\n }\n }\n\n private getCacheKey(check: PermissionCheck): string {\n const contextKey = check.context ? JSON.stringify(check.context) : '';\n return `${check.userId}:${check.resource}:${check.action}:${check.resourceId || ''}:${contextKey}`;\n }\n\n private getFromCache(key: string): PermissionResult | null {\n const expiry = this.cacheExpiry.get(key);\n if (!expiry || expiry < Date.now()) {\n this.permissionCache.delete(key);\n this.cacheExpiry.delete(key);\n return null;\n }\n\n return this.permissionCache.get(key) || null;\n }\n\n private setCache(key: string, result: PermissionResult): void {\n this.permissionCache.set(key, result);\n this.cacheExpiry.set(key, Date.now() + this.CACHE_DURATION);\n }\n\n private generateUserId(): string {\n return `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private generateRoleId(): string {\n return `role_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","/**\n * Business Verification System\n * 사업자 정보 및 서류 검증 시스템\n */\n\nimport { EventEmitter } from 'events';\nimport {\n VerificationDocument,\n DocumentType,\n DocumentStatus,\n VerificationStatus,\n Channel\n} from '../types/channel.types';\n\nexport interface BusinessInfo {\n businessName: string;\n businessRegistrationNumber: string;\n businessType: 'corporation' | 'individual' | 'partnership' | 'other';\n industry: string;\n establishedDate: Date;\n address: {\n street: string;\n city: string;\n state: string;\n postalCode: string;\n country: string;\n };\n contactInfo: {\n phoneNumber: string;\n email: string;\n website?: string;\n };\n representatives: Array<{\n name: string;\n position: string;\n phoneNumber: string;\n email: string;\n }>;\n}\n\nexport interface VerificationRequest {\n id: string;\n channelId: string;\n businessInfo: BusinessInfo;\n documents: VerificationDocument[];\n status: VerificationStatus;\n submittedAt: Date;\n reviewedAt?: Date;\n reviewedBy?: string;\n reviewNotes?: string;\n autoVerificationResults?: AutoVerificationResult[];\n}\n\nexport interface AutoVerificationResult {\n checkType: 'business_registry' | 'document_validation' | 'address_verification' | 'phone_verification';\n status: 'passed' | 'failed' | 'warning';\n score: number; // 0-100\n details: string;\n metadata?: Record<string, any>;\n}\n\nexport interface DocumentValidationResult {\n isValid: boolean;\n confidence: number; // 0-100\n extractedData?: Record<string, any>;\n issues: Array<{\n type: 'format' | 'content' | 'quality' | 'authenticity';\n severity: 'low' | 'medium' | 'high' | 'critical';\n message: string;\n }>;\n}\n\nexport interface BusinessVerifierOptions {\n enableAutoVerification: boolean;\n requiredDocuments: DocumentType[];\n autoApprovalThreshold: number; // 0-100\n requireManualReview: boolean;\n documentRetentionDays: number;\n enableExternalAPIs: boolean;\n externalAPIConfig?: {\n businessRegistryAPI?: string;\n addressVerificationAPI?: string;\n documentOCRAPI?: string;\n };\n}\n\nexport class BusinessVerifier extends EventEmitter {\n private verificationRequests = new Map<string, VerificationRequest>();\n private documentValidators = new Map<DocumentType, (doc: VerificationDocument) => Promise<DocumentValidationResult>>();\n\n private defaultOptions: BusinessVerifierOptions = {\n enableAutoVerification: true,\n requiredDocuments: [DocumentType.BUSINESS_REGISTRATION],\n autoApprovalThreshold: 80,\n requireManualReview: false,\n documentRetentionDays: 365,\n enableExternalAPIs: false\n };\n\n constructor(private options: Partial<BusinessVerifierOptions> = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n this.initializeDocumentValidators();\n }\n\n /**\n * Submit business verification request\n */\n async submitVerification(\n channelId: string,\n businessInfo: BusinessInfo,\n documents: VerificationDocument[]\n ): Promise<VerificationRequest> {\n const requestId = this.generateRequestId();\n \n // Validate required documents\n this.validateRequiredDocuments(documents);\n\n const verificationRequest: VerificationRequest = {\n id: requestId,\n channelId,\n businessInfo,\n documents: documents.map(doc => ({\n ...doc,\n status: DocumentStatus.UPLOADED\n })),\n status: VerificationStatus.PENDING,\n submittedAt: new Date()\n };\n\n this.verificationRequests.set(requestId, verificationRequest);\n\n this.emit('verification:submitted', { verificationRequest });\n\n // Start verification process\n if (this.options.enableAutoVerification) {\n await this.processAutoVerification(requestId);\n }\n\n return verificationRequest;\n }\n\n /**\n * Get verification request by ID\n */\n getVerificationRequest(requestId: string): VerificationRequest | null {\n return this.verificationRequests.get(requestId) || null;\n }\n\n /**\n * Get verification request by channel ID\n */\n getVerificationByChannelId(channelId: string): VerificationRequest | null {\n for (const request of this.verificationRequests.values()) {\n if (request.channelId === channelId) {\n return request;\n }\n }\n return null;\n }\n\n /**\n * Manually approve verification\n */\n async approveVerification(\n requestId: string,\n reviewerId: string,\n notes?: string\n ): Promise<VerificationRequest> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n throw new Error('Verification request not found');\n }\n\n request.status = VerificationStatus.VERIFIED;\n request.reviewedAt = new Date();\n request.reviewedBy = reviewerId;\n request.reviewNotes = notes;\n\n // Mark all documents as verified\n request.documents.forEach(doc => {\n doc.status = DocumentStatus.VERIFIED;\n });\n\n this.emit('verification:approved', { verificationRequest: request, reviewerId });\n\n return request;\n }\n\n /**\n * Manually reject verification\n */\n async rejectVerification(\n requestId: string,\n reviewerId: string,\n reason: string\n ): Promise<VerificationRequest> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n throw new Error('Verification request not found');\n }\n\n request.status = VerificationStatus.REJECTED;\n request.reviewedAt = new Date();\n request.reviewedBy = reviewerId;\n request.reviewNotes = reason;\n\n // Mark problematic documents as rejected\n request.documents.forEach(doc => {\n if (doc.status === DocumentStatus.UPLOADED) {\n doc.status = DocumentStatus.REJECTED;\n }\n });\n\n this.emit('verification:rejected', { verificationRequest: request, reviewerId, reason });\n\n return request;\n }\n\n /**\n * Update verification request with additional documents\n */\n async addDocument(\n requestId: string,\n document: VerificationDocument\n ): Promise<VerificationRequest> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n throw new Error('Verification request not found');\n }\n\n if (request.status !== VerificationStatus.PENDING && request.status !== VerificationStatus.UNDER_REVIEW) {\n throw new Error('Cannot add documents to completed verification');\n }\n\n document.status = DocumentStatus.UPLOADED;\n request.documents.push(document);\n\n // If auto verification is enabled, re-process\n if (this.options.enableAutoVerification) {\n await this.processAutoVerification(requestId);\n }\n\n this.emit('verification:document_added', { verificationRequest: request, document });\n\n return request;\n }\n\n /**\n * List verification requests with filters\n */\n listVerificationRequests(filters?: {\n status?: VerificationStatus;\n channelId?: string;\n submittedAfter?: Date;\n submittedBefore?: Date;\n }): VerificationRequest[] {\n let requests = Array.from(this.verificationRequests.values());\n\n if (filters?.status) {\n requests = requests.filter(r => r.status === filters.status);\n }\n if (filters?.channelId) {\n requests = requests.filter(r => r.channelId === filters.channelId);\n }\n if (filters?.submittedAfter) {\n requests = requests.filter(r => r.submittedAt >= filters.submittedAfter!);\n }\n if (filters?.submittedBefore) {\n requests = requests.filter(r => r.submittedAt <= filters.submittedBefore!);\n }\n\n return requests.sort((a, b) => b.submittedAt.getTime() - a.submittedAt.getTime());\n }\n\n /**\n * Get verification statistics\n */\n getVerificationStats(): {\n total: number;\n byStatus: Record<string, number>;\n averageProcessingTime: number;\n autoApprovalRate: number;\n } {\n const requests = Array.from(this.verificationRequests.values());\n \n const byStatus: Record<string, number> = {};\n let totalProcessingTime = 0;\n let processedCount = 0;\n let autoApprovedCount = 0;\n\n requests.forEach(request => {\n byStatus[request.status] = (byStatus[request.status] || 0) + 1;\n\n if (request.reviewedAt) {\n const processingTime = request.reviewedAt.getTime() - request.submittedAt.getTime();\n totalProcessingTime += processingTime;\n processedCount++;\n\n // Check if it was auto-approved (no manual reviewer)\n if (!request.reviewedBy && request.status === VerificationStatus.VERIFIED) {\n autoApprovedCount++;\n }\n }\n });\n\n return {\n total: requests.length,\n byStatus,\n averageProcessingTime: processedCount > 0 ? totalProcessingTime / processedCount : 0,\n autoApprovalRate: processedCount > 0 ? (autoApprovedCount / processedCount) * 100 : 0\n };\n }\n\n // Private Methods\n private async processAutoVerification(requestId: string): Promise<void> {\n const request = this.verificationRequests.get(requestId);\n if (!request) return;\n\n request.status = VerificationStatus.UNDER_REVIEW;\n this.emit('verification:auto_processing_started', { verificationRequest: request });\n\n const autoResults: AutoVerificationResult[] = [];\n\n try {\n // 1. Validate business registration\n const businessCheck = await this.verifyBusinessRegistration(request.businessInfo);\n autoResults.push(businessCheck);\n\n // 2. Validate documents\n for (const document of request.documents) {\n const docValidation = await this.validateDocument(document);\n autoResults.push({\n checkType: 'document_validation',\n status: docValidation.isValid ? 'passed' : 'failed',\n score: docValidation.confidence,\n details: `Document validation: ${docValidation.issues.length} issues found`,\n metadata: { documentId: document.id, issues: docValidation.issues }\n });\n }\n\n // 3. Verify address\n const addressCheck = await this.verifyAddress(request.businessInfo.address);\n autoResults.push(addressCheck);\n\n // 4. Verify phone number\n const phoneCheck = await this.verifyPhoneNumber(request.businessInfo.contactInfo.phoneNumber);\n autoResults.push(phoneCheck);\n\n request.autoVerificationResults = autoResults;\n\n // Calculate overall score\n const overallScore = autoResults.reduce((sum, result) => sum + result.score, 0) / autoResults.length;\n\n // Auto-approve if score is high enough\n if (overallScore >= this.options.autoApprovalThreshold! && !this.options.requireManualReview) {\n request.status = VerificationStatus.VERIFIED;\n request.reviewedAt = new Date();\n request.reviewNotes = `Auto-approved with score: ${overallScore.toFixed(1)}`;\n\n // Mark documents as verified\n request.documents.forEach(doc => {\n doc.status = DocumentStatus.VERIFIED;\n });\n\n this.emit('verification:auto_approved', { verificationRequest: request, score: overallScore });\n } else {\n // Requires manual review\n this.emit('verification:manual_review_required', { verificationRequest: request, score: overallScore });\n }\n\n } catch (error) {\n request.status = VerificationStatus.PENDING;\n this.emit('verification:auto_processing_failed', { \n verificationRequest: request, \n error: error instanceof Error ? error.message : 'Unknown error' \n });\n }\n }\n\n private validateRequiredDocuments(documents: VerificationDocument[]): void {\n const providedTypes = new Set(documents.map(doc => doc.type));\n const missingTypes = this.options.requiredDocuments!.filter(type => !providedTypes.has(type));\n\n if (missingTypes.length > 0) {\n throw new Error(`Missing required documents: ${missingTypes.join(', ')}`);\n }\n }\n\n private async verifyBusinessRegistration(businessInfo: BusinessInfo): Promise<AutoVerificationResult> {\n // In a real implementation, this would call external business registry APIs\n // For demo purposes, we'll simulate the verification\n \n const score = this.calculateBusinessRegistrationScore(businessInfo);\n \n return {\n checkType: 'business_registry',\n status: score >= 70 ? 'passed' : score >= 50 ? 'warning' : 'failed',\n score,\n details: `Business registration verification completed`,\n metadata: {\n businessName: businessInfo.businessName,\n registrationNumber: businessInfo.businessRegistrationNumber\n }\n };\n }\n\n private calculateBusinessRegistrationScore(businessInfo: BusinessInfo): number {\n let score = 0;\n\n // Check business registration number format (Korean format)\n if (/^\\d{3}-\\d{2}-\\d{5}$/.test(businessInfo.businessRegistrationNumber)) {\n score += 30;\n }\n\n // Check if business name is reasonable\n if (businessInfo.businessName.length >= 2 && businessInfo.businessName.length <= 100) {\n score += 20;\n }\n\n // Check if established date is reasonable\n const now = new Date();\n const establishedDate = new Date(businessInfo.establishedDate);\n const yearsOld = (now.getTime() - establishedDate.getTime()) / (1000 * 60 * 60 * 24 * 365);\n \n if (yearsOld >= 0 && yearsOld <= 100) {\n score += 20;\n }\n\n // Check contact information completeness\n if (businessInfo.contactInfo.email && businessInfo.contactInfo.phoneNumber) {\n score += 15;\n }\n\n // Check address completeness\n if (businessInfo.address.street && businessInfo.address.city && businessInfo.address.postalCode) {\n score += 15;\n }\n\n return Math.min(100, score);\n }\n\n private async validateDocument(document: VerificationDocument): Promise<DocumentValidationResult> {\n const validator = this.documentValidators.get(document.type);\n if (!validator) {\n return {\n isValid: false,\n confidence: 0,\n issues: [{\n type: 'format',\n severity: 'critical',\n message: `No validator available for document type: ${document.type}`\n }]\n };\n }\n\n return await validator(document);\n }\n\n private async verifyAddress(address: BusinessInfo['address']): Promise<AutoVerificationResult> {\n // Simulate address verification\n let score = 0;\n\n if (address.street && address.city && address.postalCode) {\n score += 40;\n }\n\n // Check postal code format (Korean format)\n if (/^\\d{5}$/.test(address.postalCode)) {\n score += 30;\n }\n\n if (address.country === 'KR' || address.country === 'Korea') {\n score += 30;\n }\n\n return {\n checkType: 'address_verification',\n status: score >= 70 ? 'passed' : score >= 50 ? 'warning' : 'failed',\n score,\n details: 'Address verification completed',\n metadata: { address }\n };\n }\n\n private async verifyPhoneNumber(phoneNumber: string): Promise<AutoVerificationResult> {\n // Korean phone number validation\n const isValidFormat = /^(010|011|016|017|018|019)[0-9]{7,8}$/.test(phoneNumber);\n \n const score = isValidFormat ? 100 : 0;\n\n return {\n checkType: 'phone_verification',\n status: isValidFormat ? 'passed' : 'failed',\n score,\n details: isValidFormat ? 'Phone number format is valid' : 'Invalid phone number format',\n metadata: { phoneNumber }\n };\n }\n\n private initializeDocumentValidators(): void {\n // Business Registration Document Validator\n this.documentValidators.set(DocumentType.BUSINESS_REGISTRATION, async (doc) => {\n const issues: DocumentValidationResult['issues'] = [];\n let confidence = 80; // Base confidence\n\n // Check file extension\n if (!doc.fileName.match(/\\.(pdf|jpg|jpeg|png)$/i)) {\n issues.push({\n type: 'format',\n severity: 'medium',\n message: 'Unsupported file format'\n });\n confidence -= 20;\n }\n\n // In a real implementation, would use OCR to extract and validate content\n \n return {\n isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n confidence: Math.max(0, confidence),\n issues\n };\n });\n\n // Business License Document Validator\n this.documentValidators.set(DocumentType.BUSINESS_LICENSE, async (doc) => {\n const issues: DocumentValidationResult['issues'] = [];\n let confidence = 75;\n\n if (!doc.fileName.match(/\\.(pdf|jpg|jpeg|png)$/i)) {\n issues.push({\n type: 'format',\n severity: 'medium',\n message: 'Unsupported file format'\n });\n confidence -= 15;\n }\n\n return {\n isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n confidence: Math.max(0, confidence),\n issues\n };\n });\n\n // ID Card Document Validator\n this.documentValidators.set(DocumentType.ID_CARD, async (doc) => {\n const issues: DocumentValidationResult['issues'] = [];\n let confidence = 70;\n\n if (!doc.fileName.match(/\\.(jpg|jpeg|png)$/i)) {\n issues.push({\n type: 'format',\n severity: 'high',\n message: 'ID card should be an image file'\n });\n confidence -= 30;\n }\n\n return {\n isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n confidence: Math.max(0, confidence),\n issues\n };\n });\n\n // Default validator for other document types\n const defaultValidator = async (doc: VerificationDocument): Promise<DocumentValidationResult> => {\n const issues: DocumentValidationResult['issues'] = [];\n let confidence = 60; // Lower confidence for unknown document types\n\n if (!doc.fileName || doc.fileName.length === 0) {\n issues.push({\n type: 'format',\n severity: 'critical',\n message: 'File name is required'\n });\n confidence = 0;\n }\n\n return {\n isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n confidence: Math.max(0, confidence),\n issues\n };\n };\n\n this.documentValidators.set(DocumentType.AUTHORIZATION_LETTER, defaultValidator);\n this.documentValidators.set(DocumentType.OTHER, defaultValidator);\n }\n\n private generateRequestId(): string {\n return `biz_verify_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","/**\n * Phone Number Verification System\n * 발신번호 인증 및 검증 시스템\n */\n\nimport { EventEmitter } from 'events';\nimport { SenderNumber, SenderNumberStatus, SenderNumberCategory } from '../types/channel.types';\n\nexport interface PhoneVerificationRequest {\n id: string;\n senderNumberId: string;\n phoneNumber: string;\n verificationType: VerificationType;\n verificationCode: string;\n status: PhoneVerificationStatus;\n attempts: VerificationAttempt[];\n expiresAt: Date;\n createdAt: Date;\n completedAt?: Date;\n metadata: {\n userAgent?: string;\n ipAddress?: string;\n deviceId?: string;\n smsProvider?: string;\n callProvider?: string;\n };\n}\n\nexport interface VerificationAttempt {\n attemptNumber: number;\n attemptedAt: Date;\n method: VerificationMethod;\n status: 'sent' | 'delivered' | 'failed' | 'verified' | 'expired';\n failureReason?: string;\n responseTime?: number; // in milliseconds\n}\n\nexport enum VerificationType {\n SMS = 'sms',\n VOICE_CALL = 'voice_call',\n HYBRID = 'hybrid' // Try SMS first, fallback to voice\n}\n\nexport enum VerificationMethod {\n SMS = 'sms',\n VOICE_CALL = 'voice_call',\n MISSED_CALL = 'missed_call'\n}\n\nexport enum PhoneVerificationStatus {\n PENDING = 'pending',\n CODE_SENT = 'code_sent',\n VERIFIED = 'verified',\n FAILED = 'failed',\n EXPIRED = 'expired',\n BLOCKED = 'blocked'\n}\n\nexport interface NumberVerifierOptions {\n codeLength: number;\n codeExpiryMinutes: number;\n maxAttempts: number;\n maxDailyAttempts: number;\n smsTemplate: string;\n voiceTemplate: string;\n rateLimitMinutes: number;\n enableVoiceFallback: boolean;\n enableMissedCallVerification: boolean;\n blockedNumbers: string[];\n allowedCountries: string[];\n smsProvider?: SMSProvider;\n voiceProvider?: VoiceProvider;\n}\n\nexport interface SMSProvider {\n id: string;\n name: string;\n sendSMS(phoneNumber: string, message: string, options?: any): Promise<SMSResult>;\n getDeliveryStatus?(messageId: string): Promise<DeliveryStatus>;\n}\n\nexport interface VoiceProvider {\n id: string;\n name: string;\n makeCall(phoneNumber: string, message: string, options?: any): Promise<VoiceResult>;\n makeMissedCall?(phoneNumber: string, options?: any): Promise<MissedCallResult>;\n}\n\nexport interface SMSResult {\n messageId: string;\n status: 'sent' | 'failed';\n cost?: number;\n error?: string;\n}\n\nexport interface VoiceResult {\n callId: string;\n status: 'initiated' | 'answered' | 'failed' | 'busy' | 'no_answer';\n duration?: number;\n cost?: number;\n error?: string;\n}\n\nexport interface MissedCallResult {\n callId: string;\n status: 'initiated' | 'completed' | 'failed';\n missedCallNumber?: string;\n error?: string;\n}\n\nexport interface DeliveryStatus {\n messageId: string;\n status: 'pending' | 'delivered' | 'failed' | 'expired';\n deliveredAt?: Date;\n failureReason?: string;\n}\n\nexport interface PhoneNumberInfo {\n phoneNumber: string;\n countryCode: string;\n nationalNumber: string;\n carrier?: string;\n lineType?: 'mobile' | 'landline' | 'voip' | 'unknown';\n isValid: boolean;\n isPossible: boolean;\n region?: string;\n}\n\nexport class NumberVerifier extends EventEmitter {\n private verificationRequests = new Map<string, PhoneVerificationRequest>();\n private phoneNumberCache = new Map<string, PhoneNumberInfo>();\n private rateLimitTracker = new Map<string, Date[]>();\n private dailyAttemptTracker = new Map<string, { date: string; count: number }>();\n private blockedNumbers = new Set<string>();\n\n private defaultOptions: NumberVerifierOptions = {\n codeLength: 6,\n codeExpiryMinutes: 5,\n maxAttempts: 3,\n maxDailyAttempts: 10,\n smsTemplate: '인증번호: {code}. {expiry}분 내에 입력해주세요.',\n voiceTemplate: '인증번호는 {code}입니다. 다시 한 번, {code}입니다.',\n rateLimitMinutes: 1,\n enableVoiceFallback: true,\n enableMissedCallVerification: false,\n blockedNumbers: [],\n allowedCountries: ['KR']\n };\n\n constructor(private options: Partial<NumberVerifierOptions> = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n \n // Initialize blocked numbers\n this.options.blockedNumbers?.forEach(number => {\n this.blockedNumbers.add(number);\n });\n }\n\n /**\n * Start phone number verification process\n */\n async startVerification(\n senderNumberId: string,\n phoneNumber: string,\n verificationType: VerificationType = VerificationType.SMS,\n metadata: PhoneVerificationRequest['metadata'] = {}\n ): Promise<PhoneVerificationRequest> {\n // Validate phone number\n const phoneInfo = await this.getPhoneNumberInfo(phoneNumber);\n if (!phoneInfo.isValid) {\n throw new Error('Invalid phone number format');\n }\n\n // Check if number is blocked\n if (this.isNumberBlocked(phoneNumber)) {\n throw new Error('Phone number is blocked');\n }\n\n // Check rate limiting\n if (this.isRateLimited(phoneNumber)) {\n throw new Error('Rate limit exceeded. Please try again later.');\n }\n\n // Check daily attempt limit\n if (this.isDailyLimitExceeded(phoneNumber)) {\n throw new Error('Daily verification attempt limit exceeded');\n }\n\n const requestId = this.generateRequestId();\n const verificationCode = this.generateVerificationCode();\n const expiresAt = new Date(Date.now() + this.options.codeExpiryMinutes! * 60 * 1000);\n\n const verificationRequest: PhoneVerificationRequest = {\n id: requestId,\n senderNumberId,\n phoneNumber,\n verificationType,\n verificationCode,\n status: PhoneVerificationStatus.PENDING,\n attempts: [],\n expiresAt,\n createdAt: new Date(),\n metadata\n };\n\n this.verificationRequests.set(requestId, verificationRequest);\n this.updateRateLimit(phoneNumber);\n this.updateDailyAttempts(phoneNumber);\n\n this.emit('verification:started', { verificationRequest, phoneInfo });\n\n // Send verification code\n await this.sendVerificationCode(verificationRequest, phoneInfo);\n\n return verificationRequest;\n }\n\n /**\n * Verify the provided code\n */\n async verifyCode(requestId: string, providedCode: string): Promise<{\n success: boolean;\n status: PhoneVerificationStatus;\n message: string;\n }> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n return {\n success: false,\n status: PhoneVerificationStatus.FAILED,\n message: 'Verification request not found'\n };\n }\n\n // Check if already verified\n if (request.status === PhoneVerificationStatus.VERIFIED) {\n return {\n success: true,\n status: PhoneVerificationStatus.VERIFIED,\n message: 'Already verified'\n };\n }\n\n // Check if expired\n if (new Date() > request.expiresAt) {\n request.status = PhoneVerificationStatus.EXPIRED;\n this.emit('verification:expired', { verificationRequest: request });\n \n return {\n success: false,\n status: PhoneVerificationStatus.EXPIRED,\n message: 'Verification code has expired'\n };\n }\n\n // Check if blocked due to too many attempts\n if (request.status === PhoneVerificationStatus.BLOCKED) {\n return {\n success: false,\n status: PhoneVerificationStatus.BLOCKED,\n message: 'Verification blocked due to too many failed attempts'\n };\n }\n\n // Verify code\n const isCodeValid = this.validateCode(request.verificationCode, providedCode);\n \n if (isCodeValid) {\n request.status = PhoneVerificationStatus.VERIFIED;\n request.completedAt = new Date();\n\n this.emit('verification:success', { verificationRequest: request });\n\n return {\n success: true,\n status: PhoneVerificationStatus.VERIFIED,\n message: 'Phone number verified successfully'\n };\n } else {\n // Add failed verification attempt\n const failedAttempt: VerificationAttempt = {\n attemptNumber: request.attempts.length + 1,\n attemptedAt: new Date(),\n method: VerificationMethod.SMS, // Assuming SMS for verification attempts\n status: 'failed'\n };\n request.attempts.push(failedAttempt);\n\n // Handle failed attempt\n const failedAttempts = request.attempts.filter(a => a.status === 'failed').length;\n \n if (failedAttempts >= this.options.maxAttempts!) {\n request.status = PhoneVerificationStatus.BLOCKED;\n this.emit('verification:blocked', { verificationRequest: request });\n \n return {\n success: false,\n status: PhoneVerificationStatus.BLOCKED,\n message: 'Too many failed attempts. Verification blocked.'\n };\n } else {\n request.status = PhoneVerificationStatus.FAILED;\n this.emit('verification:failed_attempt', { \n verificationRequest: request, \n attemptsRemaining: this.options.maxAttempts! - failedAttempts \n });\n\n return {\n success: false,\n status: PhoneVerificationStatus.FAILED,\n message: `Invalid code. ${this.options.maxAttempts! - failedAttempts} attempts remaining.`\n };\n }\n }\n }\n\n /**\n * Resend verification code\n */\n async resendCode(requestId: string, method?: VerificationMethod): Promise<PhoneVerificationRequest> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n throw new Error('Verification request not found');\n }\n\n if (request.status === PhoneVerificationStatus.VERIFIED) {\n throw new Error('Verification already completed');\n }\n\n if (request.status === PhoneVerificationStatus.BLOCKED) {\n throw new Error('Verification is blocked');\n }\n\n // Check rate limiting\n if (this.isRateLimited(request.phoneNumber)) {\n throw new Error('Rate limit exceeded. Please wait before requesting a new code.');\n }\n\n // Generate new code and extend expiry\n request.verificationCode = this.generateVerificationCode();\n request.expiresAt = new Date(Date.now() + this.options.codeExpiryMinutes! * 60 * 1000);\n request.status = PhoneVerificationStatus.PENDING;\n\n this.updateRateLimit(request.phoneNumber);\n\n const phoneInfo = await this.getPhoneNumberInfo(request.phoneNumber);\n \n // Send using specified method or fallback logic\n if (method) {\n await this.sendVerificationByMethod(request, phoneInfo, method);\n } else {\n await this.sendVerificationCode(request, phoneInfo);\n }\n\n this.emit('verification:resent', { verificationRequest: request });\n\n return request;\n }\n\n /**\n * Get verification request status\n */\n getVerificationStatus(requestId: string): PhoneVerificationRequest | null {\n return this.verificationRequests.get(requestId) || null;\n }\n\n /**\n * Cancel verification request\n */\n async cancelVerification(requestId: string): Promise<boolean> {\n const request = this.verificationRequests.get(requestId);\n if (!request) {\n return false;\n }\n\n if (request.status === PhoneVerificationStatus.VERIFIED) {\n return false; // Cannot cancel completed verification\n }\n\n this.verificationRequests.delete(requestId);\n this.emit('verification:cancelled', { verificationRequest: request });\n\n return true;\n }\n\n /**\n * Block a phone number from verification\n */\n blockPhoneNumber(phoneNumber: string, reason?: string): void {\n this.blockedNumbers.add(phoneNumber);\n \n // Cancel any pending verifications for this number\n for (const [requestId, request] of this.verificationRequests) {\n if (request.phoneNumber === phoneNumber && \n request.status !== PhoneVerificationStatus.VERIFIED) {\n request.status = PhoneVerificationStatus.BLOCKED;\n }\n }\n\n this.emit('phone:blocked', { phoneNumber, reason });\n }\n\n /**\n * Unblock a phone number\n */\n unblockPhoneNumber(phoneNumber: string): void {\n this.blockedNumbers.delete(phoneNumber);\n this.emit('phone:unblocked', { phoneNumber });\n }\n\n /**\n * Get verification statistics\n */\n getVerificationStats(): {\n total: number;\n byStatus: Record<string, number>;\n byMethod: Record<string, number>;\n successRate: number;\n averageCompletionTime: number;\n } {\n const requests = Array.from(this.verificationRequests.values());\n \n const byStatus: Record<string, number> = {};\n const byMethod: Record<string, number> = {};\n let totalCompletionTime = 0;\n let completedCount = 0;\n\n requests.forEach(request => {\n byStatus[request.status] = (byStatus[request.status] || 0) + 1;\n\n // Count by primary method used\n if (request.attempts.length > 0) {\n const primaryMethod = request.attempts[0].method;\n byMethod[primaryMethod] = (byMethod[primaryMethod] || 0) + 1;\n }\n\n // Calculate completion time for verified requests\n if (request.completedAt) {\n const completionTime = request.completedAt.getTime() - request.createdAt.getTime();\n totalCompletionTime += completionTime;\n completedCount++;\n }\n });\n\n const successCount = byStatus[PhoneVerificationStatus.VERIFIED] || 0;\n const successRate = requests.length > 0 ? (successCount / requests.length) * 100 : 0;\n\n return {\n total: requests.length,\n byStatus,\n byMethod,\n successRate,\n averageCompletionTime: completedCount > 0 ? totalCompletionTime / completedCount : 0\n };\n }\n\n /**\n * Clean up expired verification requests\n */\n cleanup(): number {\n const now = new Date();\n let cleanedCount = 0;\n\n for (const [requestId, request] of this.verificationRequests) {\n if (now > request.expiresAt && request.status !== PhoneVerificationStatus.VERIFIED) {\n request.status = PhoneVerificationStatus.EXPIRED;\n this.verificationRequests.delete(requestId);\n cleanedCount++;\n }\n }\n\n // Clean up old rate limit entries\n const rateWindow = this.options.rateLimitMinutes! * 60 * 1000;\n for (const [phoneNumber, timestamps] of this.rateLimitTracker) {\n const validTimestamps = timestamps.filter(ts => now.getTime() - ts.getTime() < rateWindow);\n if (validTimestamps.length === 0) {\n this.rateLimitTracker.delete(phoneNumber);\n } else {\n this.rateLimitTracker.set(phoneNumber, validTimestamps);\n }\n }\n\n return cleanedCount;\n }\n\n // Private Methods\n private async sendVerificationCode(\n request: PhoneVerificationRequest,\n phoneInfo: PhoneNumberInfo\n ): Promise<void> {\n let method: VerificationMethod;\n\n switch (request.verificationType) {\n case VerificationType.SMS:\n method = VerificationMethod.SMS;\n break;\n case VerificationType.VOICE_CALL:\n method = VerificationMethod.VOICE_CALL;\n break;\n case VerificationType.HYBRID:\n // Try SMS first for mobile, voice for landline\n method = phoneInfo.lineType === 'landline' ? VerificationMethod.VOICE_CALL : VerificationMethod.SMS;\n break;\n default:\n method = VerificationMethod.SMS;\n }\n\n await this.sendVerificationByMethod(request, phoneInfo, method);\n }\n\n private async sendVerificationByMethod(\n request: PhoneVerificationRequest,\n phoneInfo: PhoneNumberInfo,\n method: VerificationMethod\n ): Promise<void> {\n const attempt: VerificationAttempt = {\n attemptNumber: request.attempts.length + 1,\n attemptedAt: new Date(),\n method,\n status: 'sent'\n };\n\n const startTime = Date.now();\n\n try {\n switch (method) {\n case VerificationMethod.SMS:\n await this.sendSMS(request, phoneInfo);\n break;\n case VerificationMethod.VOICE_CALL:\n await this.sendVoiceCall(request, phoneInfo);\n break;\n case VerificationMethod.MISSED_CALL:\n await this.sendMissedCall(request, phoneInfo);\n break;\n }\n\n attempt.status = 'delivered';\n attempt.responseTime = Date.now() - startTime;\n request.status = PhoneVerificationStatus.CODE_SENT;\n\n } catch (error) {\n attempt.status = 'failed';\n attempt.failureReason = error instanceof Error ? error.message : 'Unknown error';\n attempt.responseTime = Date.now() - startTime;\n\n // Try fallback method if enabled and this was SMS\n if (method === VerificationMethod.SMS && \n this.options.enableVoiceFallback && \n request.attempts.filter(a => a.method === VerificationMethod.VOICE_CALL).length === 0) {\n \n attempt.status = 'failed';\n request.attempts.push(attempt);\n \n // Try voice call as fallback\n await this.sendVerificationByMethod(request, phoneInfo, VerificationMethod.VOICE_CALL);\n return;\n }\n\n request.status = PhoneVerificationStatus.FAILED;\n throw error;\n }\n\n request.attempts.push(attempt);\n }\n\n private async sendSMS(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n if (!this.options.smsProvider) {\n throw new Error('SMS provider not configured');\n }\n\n const message = this.options.smsTemplate!\n .replace('{code}', request.verificationCode)\n .replace('{expiry}', this.options.codeExpiryMinutes!.toString());\n\n const result = await this.options.smsProvider.sendSMS(request.phoneNumber, message);\n \n if (result.status === 'failed') {\n throw new Error(result.error || 'SMS sending failed');\n }\n }\n\n private async sendVoiceCall(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n if (!this.options.voiceProvider) {\n throw new Error('Voice provider not configured');\n }\n\n const message = this.options.voiceTemplate!\n .replace('{code}', request.verificationCode.split('').join(' '));\n\n const result = await this.options.voiceProvider.makeCall(request.phoneNumber, message);\n \n if (result.status === 'failed') {\n throw new Error(result.error || 'Voice call failed');\n }\n }\n\n private async sendMissedCall(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n if (!this.options.voiceProvider?.makeMissedCall) {\n throw new Error('Missed call verification not supported');\n }\n\n const result = await this.options.voiceProvider.makeMissedCall(request.phoneNumber);\n \n if (result.status === 'failed') {\n throw new Error(result.error || 'Missed call failed');\n }\n\n // For missed call verification, the code is typically the last 4-6 digits of the caller ID\n if (result.missedCallNumber) {\n const codeFromNumber = result.missedCallNumber.slice(-this.options.codeLength!);\n request.verificationCode = codeFromNumber;\n }\n }\n\n private async getPhoneNumberInfo(phoneNumber: string): Promise<PhoneNumberInfo> {\n // Check cache first\n if (this.phoneNumberCache.has(phoneNumber)) {\n return this.phoneNumberCache.get(phoneNumber)!;\n }\n\n // Basic Korean phone number validation and parsing\n const phoneInfo = this.parseKoreanPhoneNumber(phoneNumber);\n \n // Cache the result\n this.phoneNumberCache.set(phoneNumber, phoneInfo);\n \n return phoneInfo;\n }\n\n private parseKoreanPhoneNumber(phoneNumber: string): PhoneNumberInfo {\n // Remove any non-digit characters\n const cleaned = phoneNumber.replace(/\\D/g, '');\n \n // Korean phone number patterns\n const mobilePattern = /^(010|011|016|017|018|019)(\\d{7,8})$/;\n const landlinePattern = /^(02|031|032|033|041|042|043|044|051|052|053|054|055|061|062|063|064)(\\d{7,8})$/;\n \n let isValid = false;\n let isPossible = false;\n let lineType: PhoneNumberInfo['lineType'] = 'unknown';\n let carrier: string | undefined;\n\n if (mobilePattern.test(cleaned)) {\n isValid = true;\n isPossible = true;\n lineType = 'mobile';\n \n const prefix = cleaned.substring(0, 3);\n switch (prefix) {\n case '010':\n carrier = 'Multiple carriers';\n break;\n case '011':\n carrier = 'SK Telecom';\n break;\n case '016':\n carrier = 'KT';\n break;\n case '017':\n carrier = 'LG U+';\n break;\n case '018':\n carrier = 'SK Telecom';\n break;\n case '019':\n carrier = 'LG U+';\n break;\n }\n } else if (landlinePattern.test(cleaned)) {\n isValid = true;\n isPossible = true;\n lineType = 'landline';\n } else if (cleaned.length >= 10 && cleaned.length <= 11) {\n isPossible = true;\n }\n\n return {\n phoneNumber: cleaned,\n countryCode: '82',\n nationalNumber: cleaned,\n carrier,\n lineType,\n isValid,\n isPossible,\n region: 'KR'\n };\n }\n\n private isNumberBlocked(phoneNumber: string): boolean {\n return this.blockedNumbers.has(phoneNumber);\n }\n\n private isRateLimited(phoneNumber: string): boolean {\n const timestamps = this.rateLimitTracker.get(phoneNumber) || [];\n const rateWindow = this.options.rateLimitMinutes! * 60 * 1000;\n const now = new Date();\n \n const recentAttempts = timestamps.filter(ts => now.getTime() - ts.getTime() < rateWindow);\n \n return recentAttempts.length >= 1; // Allow only 1 attempt per rate limit window\n }\n\n private isDailyLimitExceeded(phoneNumber: string): boolean {\n const today = new Date().toISOString().split('T')[0];\n const dailyData = this.dailyAttemptTracker.get(phoneNumber);\n \n if (!dailyData || dailyData.date !== today) {\n return false;\n }\n \n return dailyData.count >= this.options.maxDailyAttempts!;\n }\n\n private updateRateLimit(phoneNumber: string): void {\n const timestamps = this.rateLimitTracker.get(phoneNumber) || [];\n timestamps.push(new Date());\n this.rateLimitTracker.set(phoneNumber, timestamps);\n }\n\n private updateDailyAttempts(phoneNumber: string): void {\n const today = new Date().toISOString().split('T')[0];\n const dailyData = this.dailyAttemptTracker.get(phoneNumber);\n \n if (!dailyData || dailyData.date !== today) {\n this.dailyAttemptTracker.set(phoneNumber, { date: today, count: 1 });\n } else {\n dailyData.count++;\n }\n }\n\n private validateCode(expected: string, provided: string): boolean {\n return expected === provided.replace(/\\s/g, ''); // Remove spaces\n }\n\n private generateVerificationCode(): string {\n const length = this.options.codeLength!;\n let code = '';\n \n for (let i = 0; i < length; i++) {\n code += Math.floor(Math.random() * 10).toString();\n }\n \n return code;\n }\n\n private generateRequestId(): string {\n return `phone_verify_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","import type { ChannelConfig, ChannelVerificationResult, SenderNumber } from '../types/channel.types';\nimport { SenderNumberStatus } from '../types/channel.types';\n\n// Define a service-specific SenderNumber interface that extends the types from channel.types\nexport interface ServiceSenderNumber {\n phoneNumber: string;\n name?: string;\n verifiedAt?: Date;\n status: SenderNumberStatus;\n channelId: string;\n}\n\nexport class ChannelService {\n private channels: Map<string, ChannelConfig> = new Map();\n private senderNumbers: Map<string, ServiceSenderNumber> = new Map();\n\n async createChannel(channel: Omit<ChannelConfig, 'id' | 'createdAt' | 'updatedAt'>): Promise<ChannelConfig> {\n const newChannel: ChannelConfig = {\n ...channel,\n id: this.generateChannelId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n this.channels.set(newChannel.id, newChannel);\n return newChannel;\n }\n\n async getChannel(channelId: string): Promise<ChannelConfig | null> {\n return this.channels.get(channelId) || null;\n }\n\n async listChannels(providerId?: string): Promise<ChannelConfig[]> {\n const channels = Array.from(this.channels.values());\n \n if (providerId) {\n return channels.filter(c => c.providerId === providerId);\n }\n \n return channels;\n }\n\n async updateChannel(channelId: string, updates: Partial<ChannelConfig>): Promise<ChannelConfig> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error(`Channel ${channelId} not found`);\n }\n\n const updatedChannel = {\n ...channel,\n ...updates,\n updatedAt: new Date(),\n };\n\n this.channels.set(channelId, updatedChannel);\n return updatedChannel;\n }\n\n async deleteChannel(channelId: string): Promise<void> {\n this.channels.delete(channelId);\n \n // 관련 발신번호도 삭제\n for (const [key, senderNumber] of this.senderNumbers.entries()) {\n if (senderNumber.channelId === channelId) {\n this.senderNumbers.delete(key);\n }\n }\n }\n\n async addSenderNumber(channelId: string, phoneNumber: string, name?: string): Promise<ServiceSenderNumber> {\n const channel = this.channels.get(channelId);\n if (!channel) {\n throw new Error(`Channel ${channelId} not found`);\n }\n\n const senderNumber: ServiceSenderNumber = {\n phoneNumber,\n name,\n status: SenderNumberStatus.PENDING,\n channelId,\n };\n\n this.senderNumbers.set(phoneNumber, senderNumber);\n return senderNumber;\n }\n\n async verifySenderNumber(phoneNumber: string): Promise<ChannelVerificationResult> {\n const senderNumber = this.senderNumbers.get(phoneNumber);\n if (!senderNumber) {\n return {\n success: false,\n status: 'not_found',\n error: 'Sender number not found',\n };\n }\n\n // 실제 검증 로직 (API 호출 등)\n const verificationCode = Math.floor(Math.random() * 900000) + 100000;\n\n senderNumber.verifiedAt = new Date();\n senderNumber.status = SenderNumberStatus.VERIFIED;\n\n this.senderNumbers.set(phoneNumber, senderNumber);\n\n return {\n success: true,\n status: 'verified',\n verificationCode: verificationCode.toString(),\n };\n }\n\n async getSenderNumbers(channelId?: string): Promise<ServiceSenderNumber[]> {\n const senderNumbers = Array.from(this.senderNumbers.values());\n \n if (channelId) {\n return senderNumbers.filter(s => s.channelId === channelId);\n }\n \n return senderNumbers;\n }\n\n private generateChannelId(): string {\n return `ch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}"],"mappings":"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","names":["ChannelType","ChannelStatus","SenderNumberStatus","SenderNumberCategory","VerificationStatus","DocumentType","DocumentStatus","import_events","ResourceType","ActionType","PermissionScope","import_events","import_events","VerificationType","VerificationMethod"]}
|