Implement multi-language email templates

- Add language columns to email_templates table (subject_en/de, body_html_en/de, body_text_en/de)
- Update adminEmail.js routes to support language-specific templates
- Create EmailProcessor service to handle language selection based on recipient
- Update EmailConfigPage component with language tabs similar to CMS pages
- Add German translations for all email templates
- Update all email queue usage to use proper template keys
- Add missing email templates (gallery_expired, archive_complete)
- Integrate email processor service into main server startup

The system now automatically selects the appropriate language (English/German) based on the recipient's email domain or preferences.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
This commit is contained in:
2025-07-08 17:57:26 +02:00
co-authored by Claude
parent 1bc9b547c7
commit 69b56ed582
13 changed files with 564 additions and 102 deletions
+18 -29
View File
@@ -1,6 +1,7 @@
const cron = require('node-cron');
const { db } = require('../database/db');
const { archiveEvent } = require('./archiveService');
const { queueEmail } = require('./emailProcessor');
const logger = require('../utils/logger');
function startExpirationChecker() {
@@ -28,7 +29,7 @@ async function checkExpirations() {
// Check if warning email already sent
const existingWarning = await db('email_queue')
.where('event_id', event.id)
.where('email_type', 'warning')
.where('email_type', 'expiration_warning')
.first();
if (!existingWarning) {
@@ -55,15 +56,12 @@ async function queueExpirationWarning(event) {
const daysRemaining = Math.ceil((new Date(event.expires_at) - new Date()) / (1000 * 60 * 60 * 24));
// Queue email to host
await db('email_queue').insert({
event_id: event.id,
recipient_email: event.host_email,
email_type: 'warning',
email_data: JSON.stringify({
event_name: event.event_name,
days_remaining: daysRemaining,
share_link: event.share_link
})
await queueEmail(event.id, event.host_email, 'expiration_warning', {
host_name: event.host_email.split('@')[0],
event_name: event.event_name,
days_remaining: daysRemaining.toString(),
expiration_date: new Date(event.expires_at).toLocaleDateString(),
gallery_link: event.share_link
});
logger.info(`Queued expiration warning for event ${event.slug}`);
@@ -75,25 +73,16 @@ async function handleExpiredEvent(event) {
await db('events').where('id', event.id).update({ is_active: false });
// Queue expiration emails
await db('email_queue').insert([
{
event_id: event.id,
recipient_email: event.host_email,
email_type: 'expiration',
email_data: JSON.stringify({
event_name: event.event_name
})
},
{
event_id: event.id,
recipient_email: event.admin_email,
email_type: 'expiration',
email_data: JSON.stringify({
event_name: event.event_name,
event_slug: event.slug
})
}
]);
await queueEmail(event.id, event.host_email, 'gallery_expired', {
event_name: event.event_name,
admin_email: event.admin_email
});
// Also notify admin
await queueEmail(event.id, event.admin_email, 'gallery_expired', {
event_name: event.event_name,
admin_email: event.admin_email
});
// Start archiving process
await archiveEvent(event);