Skip to content

Stop dropping emails #18

Description

@sailalithkanumuri8

Sprint 2. Shared context and the definition of done are in docs/sprints/sprint-2.md.

Description

NotificationService.send claims the dedupe key before it sends. If the send fails the key is already burned, so that email never goes out, ever. MailService.send makes it worse by turning a non-2xx from Resend into a console.error and returning as though it worked.

Separately, sendReminders calls NotificationService.org() and UserDAO.findById inside its innermost loop.

Acceptance Criteria

  • A failed send does not permanently consume its dedupe key; a later run retries it
  • Concurrent runs still cannot send the same email twice. Say which guarantee you chose and make the code match
  • MailService.send reports failure to its caller, and a bad address is distinguishable from Resend being down
  • sendReminders and AttendanceService.approveRoster batch their lookups and fetch org settings once per run
  • jobs/run returns sent, skipped and failed per job. Jobs that send nothing (expireHolds, expireLapsed, closeStale) use the same shape; say in the PR how you mapped them
  • Verified with the console transport and with a deliberately broken key, confirming the failures retry next run

Other Notes

  • NotificationLogDAO.claim and NotificationService.send. A status field on the log document is probably simpler than claim-then-release; explain whichever you pick.
  • UserDAO.findSummaries already does the batched lookup, but its SUMMARY_FIELDS projection omits notificationPreferences, and Recipient makes that field optional, so dropping it in as is type-checks and silently defeats the reminders opt-out. Widen the projection first.
  • Getting sendReminders to send anything takes two steps, not one. The virtual coding event is seeded 6 days out and the reminder windows are 24 and 72 hours, so first change the day(6, ...) near the bottom of scripts/seed.ts to day(2, ...) and re-seed. The seed returns early with "Demo events already exist" when the organizer already has events, so drop the database before re-seeding. Second, the seed creates no sign-ups at all, so sign up for that shift by hand as maya@example.com, who the seed already clears — that event requires clearance. Her sign-up lands confirmed straight away: ensureUser sets waiverVersionAccepted: 1 on every seeded account and the event is requiresApproval: false. Reminders only go to confirmed.
  • No retry queue and no backoff. The runner fires hourly; that is retry enough.
  • Other tickets touch JobService.runAll too. If a job you do not recognise appears in the map on rebase, convert it to the new return shape the same way as the rest; it is a one-line change per job.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions