Added Helpdesk

Added M2M Auth
This commit is contained in:
2025-10-31 16:27:56 +01:00
parent bbd5bbab9b
commit 2eb19b36a6
7 changed files with 232 additions and 7 deletions

View File

@@ -0,0 +1,99 @@
// 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

View File

@@ -220,7 +220,8 @@ const helpdeskRoutes: FastifyPluginAsync = async (server) => {
subject,
channel_instance_id,
helpdesk_contacts(email),
helpdesk_channel_instances(config, name)
helpdesk_channel_instances(config, name),
ticket_number
`)
.eq("id", conversationId)
.single()
@@ -263,7 +264,7 @@ const helpdeskRoutes: FastifyPluginAsync = async (server) => {
const mailOptions = {
from: `"${channel?.name}" <${user}>`,
to: contact.email,
subject: conv.subject || "Antwort vom FEDEO Helpdesk",
subject: `${conv.ticket_number} | ${conv.subject}` || `${conv.ticket_number} | Antwort vom FEDEO Helpdesk`,
text,
}