import cron from 'node-cron'; import app from './app'; import { pool } from './db'; import { sendMail } from './mailer'; // Release cart holds whose expiry has passed, every 5 minutes. setInterval(async () => { try { const { rows } = await pool.query( `DELETE FROM cart_items WHERE expires_at < now() RETURNING item_id` ); for (const row of rows) { await pool.query(`UPDATE items SET status = 'available' WHERE id = $1 AND status = 'reserved'`, [row.item_id]); } } catch (err) { console.error('cart expiry sweep failed:', (err as Error).message); } }, 5 * 60 * 1000); // Daily cart reminder emails at 9am server time, for customers who opted into marketing email. cron.schedule('0 9 * * *', async () => { try { const { rows } = await pool.query(` SELECT c.email, c.name, i.name AS item_name, ci.expires_at, ci.id AS cart_item_id FROM cart_items ci JOIN carts ca ON ca.id = ci.cart_id JOIN customers c ON c.id = ca.customer_id JOIN items i ON i.id = ci.item_id WHERE c.marketing_consent = true AND (ci.last_reminder_sent_at IS NULL OR ci.last_reminder_sent_at < now() - interval '20 hours') AND ci.expires_at > now() `); const byEmail = new Map(); for (const row of rows) { if (!byEmail.has(row.email)) byEmail.set(row.email, { name: row.name, items: [] }); byEmail.get(row.email)!.items.push({ name: row.item_name, expiresAt: row.expires_at, cartItemId: row.cart_item_id }); } for (const [email, data] of byEmail) { const itemList = data.items.map(i => `
  • ${i.name} — reserved until ${i.expiresAt.toLocaleString()}
  • `).join(''); await sendMail( email, 'Items waiting in your cart', `

    Hi${data.name ? ' ' + data.name : ''},

    You still have items in your cart at Redefined Designs:

    View your cart before your reservation expires.

    ` ); const ids = data.items.map(i => i.cartItemId); await pool.query(`UPDATE cart_items SET last_reminder_sent_at = now() WHERE id = ANY($1::int[])`, [ids]); } } catch (err) { console.error('daily cart reminder job failed:', (err as Error).message); } }); const PORT = parseInt(process.env.PORT || '3000', 10); app.listen(PORT, () => console.log(`redefined-designs listening on ${PORT}`));