feat: IMAP-Posteingang fürs Ticketsystem (Mail-Antworten -> Tickets)
Neues Postfach lässt sich unter Einstellungen > E-Mail > IMAP-Posteingang einrichten (Host/Port/Verschlüsselung/Zugangsdaten/Ordner, An/Aus, Verbindungstest). Der Worker ruft es alle 2 Minuten ab (mailbox.ts) und ordnet eingehende Mails zu: 1. Betreff enthält eine Ticketnummer (T-123) UND Absender gehört nachweislich zum Kunden dieses Tickets -> wird als Kundennachricht angehängt (Status pending_staff, Discord-Benachrichtigung). 2. Sonst, wenn der Absender ein bekannter aktiver Kunde ist -> neues Ticket wird automatisch unter seinem Kundenkonto angelegt. 3. Sonst (unbekannter/nicht verifizierbarer Absender) -> landet im neuen Posteingang (/admin/inbox, UI unter /admin/posteingang) zur manuellen Zuordnung: Personal wählt einen Kunden (legt Ticket an), hängt die Mail an ein bestehendes Ticket, oder ignoriert sie. Beim ersten Aktivieren wird kein Mailbox-Bestand verarbeitet, nur ab dann neu Eingehendes (last_uid wird auf den aktuellen Stand gesetzt). Migration 024: imap_settings (Verbindung, verschlüsseltes Passwort, last_uid/last_error), inbox_messages (Warteschlange). Rechte: email.read/write für die IMAP-Verbindung (wie SMTP), tickets.read/write für den Posteingang (Zuordnung ist eine Ticket-Aktion, daher im Tickets-Modul statt eines eigenen Moduls, um keine Modulgrenzen zu verletzen). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
7d2b2947f4
commit
fe18bf0bce
11 changed files with 651 additions and 3 deletions
|
|
@ -5,6 +5,7 @@ import { discordEnabled, discordReady, startDiscord, stopDiscord } from './disco
|
|||
import { recoverStale, runOnce } from './jobs.js';
|
||||
import { enqueue } from '@kc/platform/jobs';
|
||||
import { processContractLifecycle, scheduleDueSyncs } from '@kc/connectors';
|
||||
import { checkMailbox } from './mailbox.js';
|
||||
|
||||
const log = (m: string) => console.log(JSON.stringify({ t: new Date().toISOString(), svc: 'worker', msg: m }));
|
||||
let lastLoop = Date.now();
|
||||
|
|
@ -40,6 +41,10 @@ const checkBackup = async () => {
|
|||
};
|
||||
setInterval(() => void checkBackup(), 3600_000);
|
||||
|
||||
// Ticket-Posteingang: eingehende Mails abrufen und zuordnen (siehe mailbox.ts)
|
||||
setInterval(() => void checkMailbox(log).catch((e) => log(`IMAP-Lauf fehlgeschlagen: ${(e as Error).message}`)), 120_000);
|
||||
void checkMailbox(log).catch((e) => log(`IMAP-Lauf fehlgeschlagen: ${(e as Error).message}`));
|
||||
|
||||
for (const sig of ['SIGTERM', 'SIGINT'] as const) process.on(sig, async () => { stopping = true; await stopDiscord(); await pool.end(); process.exit(0); });
|
||||
log('Worker gestartet');
|
||||
while (!stopping) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue