// modules/helpdesk/helpdesk.inbound.email.ts import { FastifyPluginAsync } from 'fastify' import { createConversation } from '../modules/helpdesk/helpdesk.conversation.service.js' import { addMessage } from '../modules/helpdesk/helpdesk.message.service.js' import { getOrCreateContact } from '../modules/helpdesk/helpdesk.contact.service.js' import {extractDomain, findCustomerOrContactByEmailOrDomain} from "../utils/helpers"; import {useNextNumberRangeNumber} from "../utils/functions"; // ------------------------------------------------------------- // 📧 Interne M2M-Route für eingehende E-Mails // ------------------------------------------------------------- const helpdeskInboundEmailRoutes: FastifyPluginAsync = async (server) => { server.post('/helpdesk/inbound-email', async (req, res) => { const { tenant_id, channel_id, from, subject, text, message_id, in_reply_to, } = req.body if (!tenant_id || !from?.address || !text) { return res.status(400).send({ error: 'Invalid payload' }) } server.log.info(`[InboundEmail] Neue Mail von ${from.address} für Tenant ${tenant_id}`) // 1️⃣ Kunde & Kontakt ermitteln const { customer, contact: contactPerson } = (await findCustomerOrContactByEmailOrDomain(server, from.address, tenant_id)) || {} // 2️⃣ Kontakt anlegen oder laden const contact = await getOrCreateContact(server, tenant_id, { email: from.address, display_name: from.name || from.address, customer_id: customer, contact_id: contactPerson, }) // 3️⃣ Konversation anhand In-Reply-To suchen let conversationId: number | null = null if (in_reply_to) { const { data: msg } = await server.supabase .from('helpdesk_messages') .select('conversation_id') .eq('external_message_id', in_reply_to) .maybeSingle() conversationId = msg?.conversation_id || null } // 4️⃣ Neue Konversation anlegen falls keine existiert let conversation if (!conversationId) { const { usedNumber } = await useNextNumberRangeNumber(server, tenant_id, 'tickets') conversation = await createConversation(server, { tenant_id, contact, channel_instance_id: channel_id, status: 'open', subject: subject || '(kein Betreff)', customer_id: customer, contact_person_id: contactPerson, ticket_number: usedNumber, }) conversationId = conversation.id } else { const { data } = await server.supabase .from('helpdesk_conversations') .select('*') .eq('id', conversationId) .single() conversation = data } // 5️⃣ Nachricht speichern await addMessage(server, { tenant_id, conversation_id: conversationId, direction: 'incoming', payload: { type: 'text', text }, external_message_id: message_id, raw_meta: { source: 'email' }, }) server.log.info(`[InboundEmail] Ticket ${conversationId} gespeichert`) return res.status(201).send({ success: true, conversation_id: conversationId, ticket_number: conversation.ticket_number, }) }) } export default helpdeskInboundEmailRoutes