All playbooksBooking Platform

Add a reminder window

Send an extra reminder, for example one week before the appointment, without duplicate or late emails.

When to use it

The product needs a reminder at a time other than the built-in 24 hours and 2 hours before the appointment, for example 7 days before.

Rules to keep

  • Reminder logic is pure and lives in src/lib/booking/reminders.ts; the cron workflow only loads data and delivers.
  • A delivery is claimed in reminder_deliveries before the email is sent: never send first and record later.
  • After a reschedule the booking revision changes and reminders become due again. Do not bypass reminderKey.

Steps

  1. Add the new window to reminderKinds in src/lib/booking/reminders.ts. Keep the list ordered from the farthest to the closest window: dueReminders sends only the last matching entry, the closest one, when the cron has been stopped. For one week before: { kind: "7d", minutesBefore: 7 * 24 * 60 } goes first.
  2. ReminderKind is derived from the list, so TypeScript now asks for a subject in reminderSubjects (src/lib/booking/workflows.ts). Write it in the language of the product.
  3. In sendDueReminders the query only loads bookings that start within 24 * 60 + 1 minutes. Replace the hard-coded value with the largest minutesBefore in reminderKinds plus one minute, otherwise the new window is never reached.
  4. No migration is needed: reminder_deliveries.kind is text and the primary key (booking_id, kind, revision) already makes each new kind idempotent.
  5. Add tests to test/notifications.test.ts for the new window:
    • it becomes due when the booking enters the window;
    • a booking created inside the window does not receive it;
    • with the cron stopped, only the closest reminder is sent;
    • a new revision makes it due again.

Done when

  • the verification commands pass;
  • the new tests cover the four cases above;
  • sendDueReminders contains no hard-coded window.