Skip to content

fix(backend): send plan and deletion emails only once - #40

Merged
icanvardar merged 3 commits into
devfrom
fix/email-dedupe
Aug 25, 2026
Merged

fix(backend): send plan and deletion emails only once#40
icanvardar merged 3 commits into
devfrom
fix/email-dedupe

Conversation

@icanvardar

@icanvardar icanvardar commented Aug 25, 2026

Copy link
Copy Markdown
Member

Summary

  • Stop Apple-only account deletion from sending its own deletion mail; Better Auth onDelete is the single sender.
  • Claim the Pro upgrade email when hasPro first becomes true so duplicate Autumn events do not resend it.

Needed to unblock devmain (#39), which requires conversation resolution.

Test plan

  • Quality gate and full CI lane are green
  • Apple-only deletion test still removes owned sessions
  • Repeated _upgradeToPro claims the email only once

Note

Medium Risk
Touches billing webhook email paths and persistent emailState; wrong claim logic could suppress or duplicate Pro upgrade emails, but behavior mirrors the existing grace-period pattern and is covered by new tests.

Overview
Adds planUpgradedEmailSent on emailState and uses it so the Plan Upgraded email is sent at most once per real upgrade, even when Autumn/webhooks call upgrade repeatedly.

_upgradeToPro now returns claimedUpgradeEmail (same idea as downgrade’s claimedGraceEmail). It claims on first transition to Pro, skips duplicate claims for users already Pro (including legacy rows with no flag), and can re-claim after _releaseUpgradeEmail sets the flag back to false. Downgrade clears planUpgradedEmailSent so a future upgrade can email again.

_handlePlanUpgrade only calls sendEmail when the claim succeeds; on send skip or failure it releases the claim so a retry can succeed. Integration tests cover repeat upgrades, release/re-claim, and legacy Pro rows.

Reviewed by Cursor Bugbot for commit 73cb3e8. Bugbot is set up for automated code reviews on this repo. Configure here.

Skip the Apple-path deletion mail so Better Auth onDelete is the single sender, and claim the Pro upgrade mail when hasPro flips to true.
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
wrapper-web Skipped Skipped Aug 25, 2026 12:11pm

Comment thread packages/backend/convex/appleNotifications.ts
Comment thread packages/backend/convex/user.ts
adapter.deleteOne does not run Better Auth onDelete, so Apple-only deletes must send the confirmation themselves. Upgrade mail is claimed with planUpgradedEmailSent and released if the send fails.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the existing fix in f378e05 for the failed-upgrade-email retry issue. _upgradeToPro now claims the upgrade email with planUpgradedEmailSent, and _handlePlanUpgrade releases that claim if the send is skipped or throws so a later Autumn event can retry. No additional code changes were needed.

I attempted to run bun run test:integration integration-tests/email-webhooks.test.ts, but this environment does not have bun installed (bun: command not found).

Open in Web View Automation 

Sent by Cursor Automation: Autofix PR review comments

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f378e05. Configure here.

Comment thread packages/backend/convex/user.ts
Unset planUpgradedEmailSent now means a legacy Pro user, not a retry. Failed sends set the flag to false so only those can claim again.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the triggered Bugbot thread is addressed by PR head 73cb3e8: _upgradeToPro now treats legacy Pro rows (hasPro === true with no planUpgradedEmailSent) as already handled, while only planUpgradedEmailSent === false claims a retry after a failed send.

No additional code changes were needed in this run; the PR branch was already at the fixing commit. Verification passed:

  • bun run test:integration email-webhooks.test.ts (6 tests passed)
  • pre-push lint and check-types hooks passed; push reported Everything up-to-date
Open in Web View Automation 

Sent by Cursor Automation: Autofix PR review comments

@icanvardar
icanvardar merged commit f824a8b into dev Aug 25, 2026
6 checks passed
@icanvardar
icanvardar deleted the fix/email-dedupe branch August 25, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant