Refactor monolithic modules and harden booking, email, and auth infrastructure.

Split oversized frontend API client, email service, and admin/booking pages into focused modules while preserving import surfaces, and add Redis-backed queues, stale booking cleanup, stronger auth, and scale deployment configs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-06-25 07:12:59 +00:00
co-authored by Cursor
parent f0e2de2834
commit 613bd7be1d
75 changed files with 7702 additions and 5580 deletions
+93
View File
@@ -0,0 +1,93 @@
// Optional Redis connection manager.
//
// Redis is entirely optional. When REDIS_URL is unset the app runs exactly as
// before with in-memory backends. When set, this module owns a single shared
// command connection plus a dedicated subscriber connection (a connection in
// subscribe mode cannot run normal commands), with auto-reconnect, capped
// backoff, and a health flag that callers and the health endpoint can read.
import Redis from 'ioredis';
let client: Redis | null = null;
let subscriber: Redis | null = null;
let healthy = false;
let initialized = false;
/** Whether Redis is configured via REDIS_URL. */
export function isRedisEnabled(): boolean {
return !!process.env.REDIS_URL;
}
/** Whether the Redis connection is currently usable. */
export function isRedisHealthy(): boolean {
return isRedisEnabled() && healthy;
}
function buildClient(label: string): Redis {
const url = process.env.REDIS_URL as string;
const instance = new Redis(url, {
// Keep the process responsive: fail fast on a per-command basis and let the
// callers degrade to their in-memory fallback rather than hanging.
maxRetriesPerRequest: 1,
enableOfflineQueue: false,
lazyConnect: false,
retryStrategy(times) {
// Capped exponential backoff for reconnects: 200ms, 400ms ... max 5s.
const delay = Math.min(times * 200, 5000);
return delay;
},
});
instance.on('connect', () => {
console.log(`[redis] (${label}) connecting`);
});
instance.on('ready', () => {
healthy = true;
console.log(`[redis] (${label}) ready`);
});
instance.on('error', (err) => {
healthy = false;
console.error(`[redis] (${label}) error:`, err?.message || err);
});
instance.on('reconnecting', () => {
healthy = false;
console.warn(`[redis] (${label}) reconnecting`);
});
instance.on('end', () => {
healthy = false;
console.warn(`[redis] (${label}) connection closed`);
});
return instance;
}
function ensureInit(): void {
if (initialized || !isRedisEnabled()) return;
initialized = true;
client = buildClient('commands');
subscriber = buildClient('subscriber');
}
/** Shared command connection, or null when Redis is not configured. */
export function getRedis(): Redis | null {
ensureInit();
return client;
}
/** Dedicated subscriber connection, or null when Redis is not configured. */
export function getSubscriber(): Redis | null {
ensureInit();
return subscriber;
}
/** Close connections (used for graceful shutdown). */
export async function closeRedis(): Promise<void> {
const tasks: Promise<unknown>[] = [];
if (client) tasks.push(client.quit().catch(() => undefined));
if (subscriber) tasks.push(subscriber.quit().catch(() => undefined));
await Promise.all(tasks);
client = null;
subscriber = null;
initialized = false;
healthy = false;
}