Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions specs/behaviors/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ The "Add to Google Calendar" control is a prefilled `calendar.google.com/calenda
Attendees get two reminder emails per event: **one week before** and **one day before** `startsAt`.

- A background sweep runs in-process every 5 minutes (the same shape as the revocation sweeper in [authorization.md](authorization.md#revocation)). Single replica, so one sweep. It runs *inside* the API process rather than as a Kubernetes CronJob or an Actions cron because the bookkeeping write has to go through the in-process write mutex ([storage.md](storage.md)); a separate process could only write by pushing a commit to the data repo and waiting for hot reload, which is a roundabout way to set one timestamp.
- The week reminder is **due** for a `scheduled` event when `now ≥ startsAt − 7d` and `now < startsAt − 24h` and `reminders.weekSentAt` is unset. The day reminder is due when `now ≥ startsAt − 24h` and `now < startsAt` and `reminders.daySentAt` is unset.
- The windows are closed-ended so a pod that was down for the whole window, or an event created inside it, skips that reminder rather than sending a "one week" note two days out. An event created less than a day ahead gets no reminders; its confirmation email is the reminder.
- The week reminder is **due** for a `scheduled` event when `startsAt − 7d ≤ now < startsAt − 6d` and `reminders.weekSentAt` is unset. The day reminder is due when `startsAt − 24h ≤ now < startsAt − 18h` and `reminders.daySentAt` is unset. Each window is one sweep-friendly band just after its mark, not everything from the mark to the event.
- The windows are narrow on purpose: a pod that was down for the whole band, or an event created after the band passed, skips that reminder rather than sending a "one week" note three days out or a "tomorrow" note at lunchtime. An event created less than seven days ahead gets only the day reminder; one created less than a day ahead gets none — its confirmation email is the reminder.
- **At-most-once:** the sweep records `reminders.<kind>SentAt = now` on the event *before* sending, in its own commit under the write mutex, then emails each going attendee. A send failure is logged and not retried; a duplicate reminder is the worse failure.
- Each reminder email goes to the attendee's `PrivateProfile.email` and includes the when/where block, the member's follow-up answer if any ("You said you're coming to work on SquadQuest"), the canonical URL, and a "Can't make it? Update your RSVP" link. The `.ics` is not re-attached — the confirmation already delivered it.
- Members who RSVP after a reminder was sent don't receive that reminder. They were just on the page.
Expand Down
Loading