export default defineEventHandler(async (event) => { try { const body = await readBody(event) // Basic validation if (!body.name) { throw createError({ statusCode: 400, statusMessage: 'Name is required' }) } if (!['email', 'push'].includes(body.type)) { throw createError({ statusCode: 400, statusMessage: 'Type must be either email or push' }) } if (body.priority && !['low', 'medium', 'high', 'critical'].includes(body.priority)) { throw createError({ statusCode: 400, statusMessage: 'Priority must be low, medium, high, or critical' }) } // Set default priority if not provided const validatedData = { ...body, priority: body.priority || 'medium' } // Get user from session const user = event.context.user if (!user) { throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) } // Start transaction const result = await prisma.$transaction(async (tx) => { // Get template if provided let templateData = null if (validatedData.template) { templateData = await tx.notification_templates.findUnique({ where: { id: validatedData.template } }) if (!templateData) { throw createError({ statusCode: 400, statusMessage: 'Template not found' }) } } // Get segment if provided let segmentData = null let estimatedReach = 0 if (validatedData.segment) { segmentData = await tx.user_segments.findFirst({ where: { value: validatedData.segment, is_active: true } }) if (!segmentData) { throw createError({ statusCode: 400, statusMessage: 'Segment not found' }) } // TODO: Calculate estimated reach based on segment estimatedReach = 1000 // Placeholder } // Create notification const notification = await tx.notifications.create({ data: { title: validatedData.name, type: 'bulk', priority: validatedData.priority, delivery_type: validatedData.scheduledAt ? 'scheduled' : 'immediate', scheduled_at: validatedData.scheduledAt ? new Date(validatedData.scheduledAt) : null, status: validatedData.scheduledAt ? 'scheduled' : 'sending', audience_type: validatedData.segment ? 'segmented' : 'all', content_type: validatedData.template ? 'template' : 'new', template_id: templateData?.id, estimated_reach: estimatedReach, created_by: user.userID.toString(), enable_tracking: true, exclude_unsubscribed: true, respect_do_not_disturb: true } }) // Create notification channel await tx.notification_channels.create({ data: { notification_id: notification.id, channel_type: validatedData.type } }) // Add segment if provided if (segmentData) { await tx.notification_user_segments.create({ data: { notification_id: notification.id, segment_id: segmentData.id } }) } // Queue for processing if immediate if (!validatedData.scheduledAt) { // Process recipients immediately await processImmediateNotification(notification.id, { type: validatedData.type, segment: validatedData.segment }, tx) } return { id: notification.id, estimatedReach } }) return result } catch (error) { console.error('Error creating batch:', error) throw error } }) // Helper function to process immediate notifications async function processImmediateNotification(notificationId, data, tx) { // Get target users based on segment const usersQuery = { select: { id: true, email: true }, where: {} } if (data.segment) { // Add segment criteria // TODO: Implement proper segment filtering } const users = await tx.users.findMany(usersQuery) // Create recipient records and queue entries for (const user of users) { const notificationRecipient = await tx.notification_recipients.create({ data: { notification_id: notificationId, user_id: user.id, email: user.email, channel_type: data.type } }) await tx.notification_queue.create({ data: { notification_id: notificationId, recipient_id: notificationRecipient.id, scheduled_for: new Date(), priority: 5 // Default priority } }) } }