UNPKG

sysrot-hub

Version:

CLI de nueva generación para proyectos Next.js 14+ con IA multi-modelo, Web3 integration, internacionalización completa y roadmap realista 2025-2026

623 lines (567 loc) 23.2 kB
import { PrismaClient, ChatRoomType, ChatRole, MessageType, NotificationType } from '@prisma/client'; import bcrypt from 'bcryptjs'; const prisma = new PrismaClient(); async function seedChat() { console.log('💬 Starting Real-time Chat seed...'); try { // Create chat users if they don't exist console.log('👥 Creating chat users...'); const passwordHash = await bcrypt.hash('chat123', 10); const users = [ { email: 'alice@team.com', name: 'Alice Johnson', image: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face' }, { email: 'bob@team.com', name: 'Bob Smith', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face' }, { email: 'carol@team.com', name: 'Carol Davis', image: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face' }, { email: 'david@team.com', name: 'David Chen', image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face' }, { email: 'eva@team.com', name: 'Eva Rodriguez', image: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&h=150&fit=crop&crop=face' }, { email: 'frank@team.com', name: 'Frank Wilson', image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=150&h=150&fit=crop&crop=face' } ]; const createdUsers = []; for (const userData of users) { const user = await prisma.user.upsert({ where: { email: userData.email }, update: {}, create: { ...userData, password: passwordHash, role: 'user', emailVerified: new Date() } }); createdUsers.push(user); } console.log('✅ Created chat users'); // Create chat rooms console.log('🏠 Creating chat rooms...'); // General team room const generalRoom = await prisma.chatRoom.upsert({ where: { id: 'general-team-room' }, update: {}, create: { id: 'general-team-room', name: 'General', description: 'General team discussions and announcements', type: ChatRoomType.CHANNEL, isPrivate: false, avatar: '💬', createdBy: createdUsers[0].id, maxMembers: 50, settings: JSON.stringify({ allowFileUploads: true, allowReactions: true, allowThreads: true, muteNotifications: false }) } }); // Development team room const devRoom = await prisma.chatRoom.upsert({ where: { id: 'dev-team-room' }, update: {}, create: { id: 'dev-team-room', name: 'Development', description: 'Development team discussions, code reviews, and tech talks', type: ChatRoomType.GROUP, isPrivate: false, avatar: '💻', createdBy: createdUsers[1].id, maxMembers: 20, settings: JSON.stringify({ allowFileUploads: true, allowReactions: true, allowThreads: true, requireApproval: false }) } }); // Design team room const designRoom = await prisma.chatRoom.upsert({ where: { id: 'design-team-room' }, update: {}, create: { id: 'design-team-room', name: 'Design', description: 'Design team creativity and feedback', type: ChatRoomType.GROUP, isPrivate: false, avatar: '🎨', createdBy: createdUsers[2].id, maxMembers: 15, settings: JSON.stringify({ allowFileUploads: true, allowReactions: true, allowThreads: true, theme: 'creative' }) } }); // Direct message room (Alice & Bob) const directRoom = await prisma.chatRoom.upsert({ where: { id: 'alice-bob-direct' }, update: {}, create: { id: 'alice-bob-direct', name: 'Alice & Bob', type: ChatRoomType.DIRECT, isPrivate: true, createdBy: createdUsers[0].id, maxMembers: 2, settings: JSON.stringify({ encryptMessages: true, deleteAfter: null }) } }); // Support room const supportRoom = await prisma.chatRoom.upsert({ where: { id: 'support-room' }, update: {}, create: { id: 'support-room', name: 'Help & Support', description: 'Get help from our support team', type: ChatRoomType.SUPPORT, isPrivate: false, avatar: '🆘', createdBy: createdUsers[3].id, maxMembers: 100, settings: JSON.stringify({ autoAssignAgent: true, businessHoursOnly: false, priority: 'high' }) } }); console.log('✅ Created chat rooms'); // Create participants console.log('👤 Creating room participants...'); const participantData = [ // General room - everyone { roomId: generalRoom.id, userId: createdUsers[0].id, role: ChatRole.OWNER, permissions: ['*'] }, { roomId: generalRoom.id, userId: createdUsers[1].id, role: ChatRole.ADMIN, permissions: ['moderate', 'invite', 'manage_messages'] }, { roomId: generalRoom.id, userId: createdUsers[2].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: generalRoom.id, userId: createdUsers[3].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: generalRoom.id, userId: createdUsers[4].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: generalRoom.id, userId: createdUsers[5].id, role: ChatRole.MEMBER, permissions: [] }, // Dev room - developers { roomId: devRoom.id, userId: createdUsers[1].id, role: ChatRole.OWNER, permissions: ['*'] }, { roomId: devRoom.id, userId: createdUsers[0].id, role: ChatRole.ADMIN, permissions: ['moderate', 'invite'] }, { roomId: devRoom.id, userId: createdUsers[3].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: devRoom.id, userId: createdUsers[4].id, role: ChatRole.MEMBER, permissions: [] }, // Design room - designers and stakeholders { roomId: designRoom.id, userId: createdUsers[2].id, role: ChatRole.OWNER, permissions: ['*'] }, { roomId: designRoom.id, userId: createdUsers[0].id, role: ChatRole.ADMIN, permissions: ['moderate'] }, { roomId: designRoom.id, userId: createdUsers[4].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: designRoom.id, userId: createdUsers[5].id, role: ChatRole.MEMBER, permissions: [] }, // Direct message { roomId: directRoom.id, userId: createdUsers[0].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: directRoom.id, userId: createdUsers[1].id, role: ChatRole.MEMBER, permissions: [] }, // Support room { roomId: supportRoom.id, userId: createdUsers[3].id, role: ChatRole.OWNER, permissions: ['*'] }, { roomId: supportRoom.id, userId: createdUsers[0].id, role: ChatRole.ADMIN, permissions: ['moderate', 'assign_tickets'] }, { roomId: supportRoom.id, userId: createdUsers[1].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: supportRoom.id, userId: createdUsers[2].id, role: ChatRole.MEMBER, permissions: [] }, { roomId: supportRoom.id, userId: createdUsers[4].id, role: ChatRole.MEMBER, permissions: [] } ]; for (const participant of participantData) { await prisma.chatParticipant.upsert({ where: { roomId_userId: { roomId: participant.roomId, userId: participant.userId } }, update: {}, create: { ...participant, joinedAt: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000), // Random join time in last 30 days lastSeenAt: new Date(Date.now() - Math.random() * 24 * 60 * 60 * 1000), // Random last seen in last 24 hours notificationSettings: JSON.stringify({ muted: false, desktop: true, mobile: true, email: false }) } }); } console.log('✅ Created room participants'); // Create sample messages console.log('💬 Creating sample messages...'); const sampleMessages = [ // General room messages { roomId: generalRoom.id, userId: createdUsers[0].id, content: '¡Bienvenidos al canal general del equipo! 🎉 Aquí compartiremos updates importantes y celebraremos nuestros logros.', type: MessageType.TEXT, createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }, { roomId: generalRoom.id, userId: createdUsers[1].id, content: '¡Excelente! Me encanta tener un espacio centralizado para el equipo. 💪', type: MessageType.TEXT, createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000 + 5 * 60 * 1000) }, { roomId: generalRoom.id, userId: createdUsers[2].id, content: 'Perfecto para mantenernos sincronizados. ¿Tendremos daily standups aquí? 🤔', type: MessageType.TEXT, createdAt: new Date(Date.now() - 6 * 24 * 60 * 60 * 1000) }, { roomId: generalRoom.id, userId: createdUsers[0].id, content: 'Great idea! Podemos hacer quick check-ins aquí los lunes, miércoles y viernes 📅', type: MessageType.TEXT, createdAt: new Date(Date.now() - 6 * 24 * 60 * 60 * 1000 + 10 * 60 * 1000) }, { roomId: generalRoom.id, userId: null, // System message content: 'Eva Rodriguez se unió al canal', type: MessageType.SYSTEM, createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000) }, { roomId: generalRoom.id, userId: createdUsers[4].id, content: '¡Hola team! Emocionada de estar aquí 🌟', type: MessageType.TEXT, createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000 + 2 * 60 * 1000) }, // Dev room messages { roomId: devRoom.id, userId: createdUsers[1].id, content: '🚀 Nueva release en staging! Pueden hacer testing de las nuevas features.', type: MessageType.TEXT, createdAt: new Date(Date.now() - 4 * 24 * 60 * 60 * 1000) }, { roomId: devRoom.id, userId: createdUsers[3].id, content: 'Awesome! ¿Ya está el user authentication funcionando? 🔐', type: MessageType.TEXT, createdAt: new Date(Date.now() - 4 * 24 * 60 * 60 * 1000 + 15 * 60 * 1000) }, { roomId: devRoom.id, userId: createdUsers[1].id, content: 'Sí! NextAuth.js está configurado con Google, GitHub y email/password 💯', type: MessageType.TEXT, createdAt: new Date(Date.now() - 4 * 24 * 60 * 60 * 1000 + 20 * 60 * 1000) }, { roomId: devRoom.id, userId: createdUsers[4].id, content: 'Perfect! ¿Necesitan help con los tests? Puedo escribir algunos e2e tests 🧪', type: MessageType.TEXT, createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000) }, { roomId: devRoom.id, userId: createdUsers[1].id, content: 'That would be amazing Eva! Los tests de Playwright estarían geniales 🎭', type: MessageType.TEXT, createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000 + 5 * 60 * 1000) }, // Design room messages { roomId: designRoom.id, userId: createdUsers[2].id, content: '🎨 Working on the new dashboard design. ¿Qué opinan de estos mockups?', type: MessageType.TEXT, createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000) }, { roomId: designRoom.id, userId: createdUsers[0].id, content: 'Love the clean aesthetic! Los colores están perfect para el branding 🌈', type: MessageType.TEXT, createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000 + 30 * 60 * 1000) }, { roomId: designRoom.id, userId: createdUsers[4].id, content: '¿Podríamos hacer the navigation un poco más accessible? Maybe larger touch targets 📱', type: MessageType.TEXT, createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000) }, { roomId: designRoom.id, userId: createdUsers[2].id, content: 'Excellent point! Accessibility es super importante. Voy a ajustar los sizes ♿', type: MessageType.TEXT, createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000 + 10 * 60 * 1000) }, // Direct messages { roomId: directRoom.id, userId: createdUsers[0].id, content: '¿Tienes tiempo for a quick sync about the project roadmap? 🗺️', type: MessageType.TEXT, createdAt: new Date(Date.now() - 3 * 60 * 60 * 1000) }, { roomId: directRoom.id, userId: createdUsers[1].id, content: 'Sure! Estoy free en 30 minutos. ¿Video call o here? 📞', type: MessageType.TEXT, createdAt: new Date(Date.now() - 2.5 * 60 * 60 * 1000) }, { roomId: directRoom.id, userId: createdUsers[0].id, content: 'Video call sería better. Sending calendar invite! 📅', type: MessageType.TEXT, createdAt: new Date(Date.now() - 2 * 60 * 60 * 1000) }, // Support room messages { roomId: supportRoom.id, userId: createdUsers[4].id, content: '🆘 Help! No puedo upload files en el dashboard. ¿Es un known issue?', type: MessageType.TEXT, createdAt: new Date(Date.now() - 4 * 60 * 60 * 1000) }, { roomId: supportRoom.id, userId: createdUsers[3].id, content: 'Hey Eva! Let me check that for you. ¿Qué browser estás usando? 🌐', type: MessageType.TEXT, createdAt: new Date(Date.now() - 4 * 60 * 60 * 1000 + 2 * 60 * 1000) }, { roomId: supportRoom.id, userId: createdUsers[4].id, content: 'Chrome Version 120 on macOS. Files are PDFs around 2MB 📄', type: MessageType.TEXT, createdAt: new Date(Date.now() - 3.5 * 60 * 60 * 1000) }, { roomId: supportRoom.id, userId: createdUsers[3].id, content: 'Found the issue! Hay un bug with PDF uploads. Fix coming in next release 🐛→✅', type: MessageType.TEXT, createdAt: new Date(Date.now() - 3 * 60 * 60 * 1000) } ]; const createdMessages = []; for (const messageData of sampleMessages) { const message = await prisma.chatMessage.create({ data: messageData }); createdMessages.push(message); } console.log('✅ Created sample messages'); // Add some threaded replies console.log('🧵 Creating threaded replies...'); const threadReplies = [ { roomId: devRoom.id, userId: createdUsers[0].id, content: 'También agregué rate limiting para security 🔒', type: MessageType.TEXT, parentId: createdMessages.find(m => m.content.includes('NextAuth.js está configurado'))?.id, createdAt: new Date(Date.now() - 4 * 24 * 60 * 60 * 1000 + 25 * 60 * 1000) }, { roomId: devRoom.id, userId: createdUsers[3].id, content: 'Nice! ¿Qué strategy usaste? Redis-based? 🏎️', type: MessageType.TEXT, parentId: createdMessages.find(m => m.content.includes('NextAuth.js está configurado'))?.id, createdAt: new Date(Date.now() - 4 * 24 * 60 * 60 * 1000 + 35 * 60 * 1000) }, { roomId: designRoom.id, userId: createdUsers[5].id, content: 'The color contrast looks great! WCAG AA compliant? ✅', type: MessageType.TEXT, parentId: createdMessages.find(m => m.content.includes('Love the clean aesthetic'))?.id, createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000 + 45 * 60 * 1000) } ]; for (const replyData of threadReplies) { if (replyData.parentId) { await prisma.chatMessage.create({ data: replyData }); } } console.log('✅ Created threaded replies'); // Add reactions to messages console.log('😊 Adding message reactions...'); const reactions = [ { messageId: createdMessages[0].id, userId: createdUsers[1].id, emoji: '🎉' }, { messageId: createdMessages[0].id, userId: createdUsers[2].id, emoji: '🎉' }, { messageId: createdMessages[0].id, userId: createdUsers[3].id, emoji: '👍' }, { messageId: createdMessages[1].id, userId: createdUsers[0].id, emoji: '💪' }, { messageId: createdMessages[1].id, userId: createdUsers[2].id, emoji: '👍' }, { messageId: createdMessages[6].id, userId: createdUsers[0].id, emoji: '🚀' }, { messageId: createdMessages[6].id, userId: createdUsers[3].id, emoji: '🔥' }, { messageId: createdMessages[6].id, userId: createdUsers[4].id, emoji: '🔥' }, { messageId: createdMessages[10].id, userId: createdUsers[1].id, emoji: '🎭' }, { messageId: createdMessages[12].id, userId: createdUsers[0].id, emoji: '🎨' }, { messageId: createdMessages[12].id, userId: createdUsers[4].id, emoji: '💯' } ]; for (const reaction of reactions) { try { await prisma.chatReaction.create({ data: reaction }); } catch (error) { // Skip if reaction already exists } } console.log('✅ Added message reactions'); // Add read receipts console.log('👁️ Creating read receipts...'); for (const message of createdMessages.slice(0, 15)) { // Add read receipts for first 15 messages const roomParticipants = await prisma.chatParticipant.findMany({ where: { roomId: message.roomId }, select: { userId: true } }); for (const participant of roomParticipants) { // Don't create read receipt for message author if (participant.userId !== message.userId) { try { await prisma.chatReadReceipt.create({ data: { messageId: message.id, userId: participant.userId, readAt: new Date(message.createdAt.getTime() + Math.random() * 60 * 60 * 1000) // Read within an hour } }); } catch (error) { // Skip if already exists } } } } console.log('✅ Created read receipts'); // Add some typing indicators (simulating current activity) console.log('⌨️ Adding typing indicators...'); const typingIndicators = [ { roomId: generalRoom.id, userId: createdUsers[5].id, isTyping: true }, { roomId: devRoom.id, userId: createdUsers[4].id, isTyping: true } ]; for (const indicator of typingIndicators) { await prisma.chatTypingIndicator.create({ data: { ...indicator, lastTypedAt: new Date() } }); } console.log('✅ Added typing indicators'); // Create some notifications console.log('🔔 Creating notifications...'); const notifications = [ { userId: createdUsers[0].id, roomId: devRoom.id, messageId: createdMessages.find(m => m.content.includes('Awesome! ¿Ya está el user authentication'))?.id, type: NotificationType.MENTION, title: 'Nueva mención en Development', content: 'David Chen te mencionó en Development', isRead: false }, { userId: createdUsers[2].id, roomId: designRoom.id, type: NotificationType.MESSAGE, title: 'Nuevo mensaje en Design', content: 'Eva Rodriguez envió un mensaje', isRead: true, readAt: new Date() }, { userId: createdUsers[1].id, roomId: directRoom.id, messageId: createdMessages.find(m => m.content.includes('tiempo for a quick sync'))?.id, type: NotificationType.MESSAGE, title: 'Mensaje directo de Alice', content: '¿Tienes tiempo for a quick sync about...', isRead: false } ]; for (const notification of notifications) { if (notification.messageId) { await prisma.chatNotification.create({ data: notification }); } } console.log('✅ Created notifications'); console.log('\n🎉 Real-time Chat seed completed successfully!'); console.log('\n📊 Summary:'); console.log(` 6 chat users created`); console.log(` 5 chat rooms created (General, Dev, Design, Direct, Support)`); console.log(` 21 room participants added`); console.log(` ${createdMessages.length} messages created`); console.log(` 3 threaded replies added`); console.log(` 11 message reactions added`); console.log(` Read receipts for active messages`); console.log(` 2 active typing indicators`); console.log(` 3 sample notifications`); console.log('\n🔑 Test Login Credentials:'); console.log(' alice@team.com:chat123 (Team Lead)'); console.log(' bob@team.com:chat123 (Senior Developer)'); console.log(' carol@team.com:chat123 (Lead Designer)'); console.log(' david@team.com:chat123 (DevOps Engineer)'); console.log(' eva@team.com:chat123 (QA Engineer)'); console.log(' frank@team.com:chat123 (Product Manager)'); console.log('\n💬 Chat Features Ready:'); console.log(' Multi-room support (Direct, Group, Channel, Support)'); console.log(' Real-time messaging with reactions'); console.log(' Threaded conversations'); console.log(' Read receipts and typing indicators'); console.log(' Role-based permissions'); console.log(' File attachments support'); console.log(' Notification system'); console.log(' Message editing and deletion'); } catch (error) { console.error('❌ Error seeding chat data:', error); throw error; } } export default seedChat; // Run the seed if this file is executed directly if (require.main === module) { seedChat() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); }); }