Email queue + async sending; legal settings and placeholders

- Add in-memory email queue with rate limiting (MAX_EMAILS_PER_HOUR)
- Bulk send to event attendees now queues and returns immediately
- Frontend shows 'Emails are being sent in the background'
- Legal pages, settings, and placeholders updates

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-02-12 21:03:49 +00:00
parent 18254c566e
commit b9f46b02cc
17 changed files with 1410 additions and 352 deletions

View File

@@ -3,6 +3,7 @@ import { db, dbGet, dbAll, legalPages } from '../db/index.js';
import { eq, desc } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { getNow, generateId } from '../lib/utils.js';
import { replaceLegalPlaceholders } from '../lib/legal-placeholders.js';
import fs from 'fs';
import path from 'path';
@@ -171,12 +172,15 @@ legalPagesRouter.get('/:slug', async (c) => {
// Get localized content with fallback
const { title, contentMarkdown } = getLocalizedContent(page, locale);
// Replace legal placeholders before returning
const processedContent = await replaceLegalPlaceholders(contentMarkdown, page.updatedAt);
return c.json({
page: {
id: page.id,
slug: page.slug,
title,
contentMarkdown,
contentMarkdown: processedContent,
updatedAt: page.updatedAt,
source: 'database',
}
@@ -195,11 +199,14 @@ legalPagesRouter.get('/:slug', async (c) => {
? (titles?.es || titles?.en || slug)
: (titles?.en || titles?.es || slug);
// Replace legal placeholders in filesystem content too
const processedContent = await replaceLegalPlaceholders(content);
return c.json({
page: {
slug,
title,
contentMarkdown: content,
contentMarkdown: processedContent,
source: 'filesystem',
}
});