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_deliveriesbefore the email is sent: never send first and record later. - After a reschedule the booking
revisionchanges and reminders become due again. Do not bypassreminderKey.
Steps
- Add the new window to
reminderKindsinsrc/lib/booking/reminders.ts. Keep the list ordered from the farthest to the closest window:dueReminderssends 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. ReminderKindis derived from the list, so TypeScript now asks for a subject inreminderSubjects(src/lib/booking/workflows.ts). Write it in the language of the product.- In
sendDueRemindersthe query only loads bookings that start within24 * 60 + 1minutes. Replace the hard-coded value with the largestminutesBeforeinreminderKindsplus one minute, otherwise the new window is never reached. - No migration is needed:
reminder_deliveries.kindis text and the primary key(booking_id, kind, revision)already makes each new kind idempotent. - Add tests to
test/notifications.test.tsfor 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
revisionmakes it due again.
Done when
- the verification commands pass;
- the new tests cover the four cases above;
sendDueReminderscontains no hard-coded window.
