feat: SMTP-Stack mit konfigurierbaren Mailvorlagen
Bisher gab es nur zwei fest im Code verdrahtete E-Mails (Einladung, Passwort-Reset) und die SMTP-Verbindung kam ausschließlich aus Umgebungsvariablen. Jetzt: - SMTP-Verbindung unter Einstellungen > E-Mail konfigurierbar (Host, Port, Verschlüsselung, Zugangsdaten verschlüsselt gespeichert, Absender), mit Testmail-Versand. Die Mail-Logik wandert dafür nach @kc/platform/mail, damit API und Worker sie gemeinsam nutzen. - Mailvorlagen-Verwaltung: jedes Ereignis hat eine feste "Definition" (Name, Auslöser, verfügbare Platzhalter/Daten), Betreff/Text sind editierbar, je Vorlage einzeln aktivierbar, mit Testversand anhand von Beispieldaten. Unbekannte Platzhalter werden beim Speichern abgelehnt. - Neue Ereignisse verdrahtet: Ticket erstellt (Bestätigung an Kunde), Personal antwortet auf Ticket (Benachrichtigung an Kunde), Rechnung ausgestellt, sowie die zuvor zurückgestellte Funktion "Panel- Zugangsdaten per E-Mail senden" nach einem Passwort-Reset. Diese laufen über die Jobqueue (mail.template), analog zu discord.notify. - Versandprotokoll (letzte 100 Versuche, ohne Inhalte) einsehbar unter Einstellungen > E-Mail. - Migration 022, Rechte email.read (Admin+) / email.write (Superadmin). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b112647ff1
commit
a68b4cf6ec
18 changed files with 385 additions and 42 deletions
54
migrations/022_mail_templates.sql
Normal file
54
migrations/022_mail_templates.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
-- SMTP-Stack: konfigurierbare Verbindung (statt Umgebungsvariablen) und Mailvorlagen mit dokumentierten Platzhaltern.
|
||||
CREATE TABLE smtp_settings (
|
||||
id TINYINT PRIMARY KEY DEFAULT 1,
|
||||
host VARCHAR(253) NULL,
|
||||
port SMALLINT UNSIGNED NOT NULL DEFAULT 587,
|
||||
secure_mode ENUM('none','starttls','tls') NOT NULL DEFAULT 'starttls',
|
||||
username VARCHAR(200) NULL,
|
||||
secrets_enc TEXT NULL,
|
||||
from_name VARCHAR(150) NULL,
|
||||
from_email VARCHAR(254) NULL,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
updated_by CHAR(36) NULL REFERENCES users(id),
|
||||
CONSTRAINT chk_smtp_singleton CHECK (id = 1)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
INSERT INTO smtp_settings (id) VALUES (1);
|
||||
|
||||
-- Vorlagen je Ereignis ("Definition"): Betreff/Text mit {{platzhalter}}, dokumentierte verfügbare Daten je Vorlage.
|
||||
CREATE TABLE mail_templates (
|
||||
`key` VARCHAR(60) PRIMARY KEY,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
trigger_text VARCHAR(300) NOT NULL,
|
||||
variables_json JSON NOT NULL,
|
||||
subject VARCHAR(300) NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
updated_by CHAR(36) NULL REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO mail_templates (`key`, name, trigger_text, variables_json, subject, body) VALUES
|
||||
('invite', 'Zugang eingerichtet', 'Wenn für einen Kunden ein neuer Zugang angelegt wird.',
|
||||
JSON_ARRAY('name','inviteLink','validDays'),
|
||||
'Ihr Zugang zum Kundencenter',
|
||||
'Hallo {{name}},\n\nfür Sie wurde ein Zugang eingerichtet. Bitte legen Sie hier Ihr Passwort fest ({{validDays}} Tage gültig):\n{{inviteLink}}\n'),
|
||||
('password_reset', 'Passwort zurücksetzen', 'Wenn ein Passwort-Reset angefordert wird (Kunde oder Personal).',
|
||||
JSON_ARRAY('name','resetLink'),
|
||||
'Passwort zurücksetzen',
|
||||
'Hallo {{name}},\n\nüber diesen Link können Sie Ihr Passwort zurücksetzen (1 Stunde gültig):\n{{resetLink}}\n\nWenn Sie das nicht angefordert haben, ignorieren Sie diese E-Mail.\n'),
|
||||
('panel_credentials', 'Neue Panel-Zugangsdaten', 'Wenn Personal nach dem Neuvergeben eines Panel-Passworts auf „Per E-Mail senden“ klickt.',
|
||||
JSON_ARRAY('name','resourceName','username','password'),
|
||||
'Ihre neuen Zugangsdaten für {{resourceName}}',
|
||||
'Hallo {{name}},\n\nfür {{resourceName}} wurden neue Zugangsdaten vergeben:\n\nBenutzername: {{username}}\nPasswort: {{password}}\n\nBitte bewahren Sie die Zugangsdaten sicher auf und ändern Sie das Passwort nach der ersten Anmeldung, falls möglich.\n'),
|
||||
('ticket_created', 'Ticket erstellt (Bestätigung an Kunde)', 'Wenn ein Kunde selbst ein neues Ticket erstellt.',
|
||||
JSON_ARRAY('name','number','subject'),
|
||||
'Ticket {{number}} wurde erstellt',
|
||||
'Hallo {{name}},\n\nIhr Ticket „{{subject}}“ ({{number}}) wurde bei uns erstellt. Wir melden uns, sobald es eine Antwort gibt.\n'),
|
||||
('ticket_message', 'Antwort auf Ticket (an Kunde)', 'Wenn Personal auf ein Kunden-Ticket antwortet (keine interne Notiz).',
|
||||
JSON_ARRAY('name','number','subject'),
|
||||
'Neue Antwort zu Ticket {{number}}',
|
||||
'Hallo {{name}},\n\nes gibt eine neue Antwort zu Ihrem Ticket „{{subject}}“ ({{number}}). Bitte im Kundencenter ansehen und bei Bedarf antworten.\n'),
|
||||
('invoice_issued', 'Rechnung erstellt', 'Wenn eine Rechnung ausgestellt wird.',
|
||||
JSON_ARRAY('name','number','amount','dueDate'),
|
||||
'Ihre Rechnung {{number}}',
|
||||
'Hallo {{name}},\n\nIhre Rechnung {{number}} über {{amount}} wurde erstellt, fällig am {{dueDate}}. Sie können sie im Kundencenter einsehen und als PDF herunterladen.\n');
|
||||
Loading…
Add table
Add a link
Reference in a new issue