Stop promising an email nobody is sending - #52
Merged
Merged
Conversation
The settings switch defaulted to on, and the digest function is a deliberate no-op without EMAIL_PROVIDER_KEY / EMAIL_FROM. So a student who never opened Settings had been told they would be emailed when a deadline was within a week, and nothing ever was — the one promise a deadline tool most needs to keep, and the highest-severity item in the readiness review. It is off until mail is live. The two sides also disagreed about what "unset" meant, which would have bitten at exactly the wrong moment. The web app read no stored value as on; the function skipped only an explicit false. Adding a provider key would therefore have mailed every student who never opened Settings — people who had been shown a switch already on but never chose it. Both now require an explicit true, so only a deliberate opt-in gets mail. Flip DEFAULT_PREFERENCES.email_reminders back once a provider is configured; that governs new accounts, and anyone who already chose keeps their choice.
Deploying timeline-prototype with
|
| Latest commit: |
0b37b4b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://75db297b.timeline-prototype.pages.dev |
| Branch Preview URL: | https://fix-no-unsent-email-promise.timeline-prototype.pages.dev |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Settings switch defaulted to on, and
deadline-digestis a deliberate no-op withoutEMAIL_PROVIDER_KEY/EMAIL_FROM.So a student who never opened Settings had been told they would be emailed when a deadline was within a week, and nothing ever was. For a deadline tool that is the one promise most worth keeping, and it was the highest-severity item in the readiness review.
It is off until mail is live.
The bug that would have bitten later
The two sides disagreed about what unset meant:
DEFAULT_PREFERENCES)falseBoth treat "never touched it" as consent. So the moment a provider key was added, the first cron run would have mailed every student who never opened Settings — people who had been shown a switch already on, but never chose it. The worse version of the original problem: not a promise unkept, but mail nobody asked for.
Both now require an explicit
true. Only a deliberate opt-in gets mail.Turning it on later
api.resend.com/emails)supabase secrets set EMAIL_PROVIDER_KEY=... EMAIL_FROM=...POST {"mode":"dry"}to confirm the recipient list looks right before anything sendsDEFAULT_PREFERENCES.email_remindersback totruefor new accounts — anyone who already chose keeps their choiceDocumented in the function's README.
Testing
485 passing, lint and typecheck clean, and the edge function type-checks under Deno. New tests pin the default off and that a student's own choice is kept either way — the default is exactly the kind of thing that regresses silently.