feat(billing): unify upgrade routing with reason context + storage/tables limit emails#5171
feat(billing): unify upgrade routing with reason context + storage/tables limit emails#5171waleedlatif1 wants to merge 8 commits into
Conversation
…bles limit emails
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview In-app limit surfaces deep-link with context: credits chip, teammates invite gate, table row errors, and storage upload failures (new Adds 80% / 100% threshold emails for storage and table rows via Reviewed by Cursor Bugbot for commit f4a9626. Configure here. |
Greptile SummaryThis PR introduces a unified upgrade-routing system with a central
Confidence Score: 5/5Safe to merge — the dedup claim is race-free, the re-arm hysteresis is correct, all email paths are fire-and-forget, and the migration is a backward-compatible additive column with a sensible default. The atomic UPDATE … WHERE current < desired RETURNING claim correctly prevents duplicate emails even under concurrent calls. The re-arm path now receives priorUsage for the tables case and uses rearmOnly=true on the storage decrement path. Per-recipient email failures are isolated in individual try/catch blocks. The new limit_notifications JSONB column ships with NOT NULL DEFAULT '{}', so existing rows are handled without a backfill. Dead-link fix for credits emails is verified correct. No regressions found in any call site. No files require special attention — the core notification logic, migration, email template, and routing changes all look correct. Important Files Changed
Reviews (5): Last reviewed commit: "fix(billing): resolve recipients before ..." | Re-trigger Greptile |
…sage + decrement)
|
@greptile |
|
@cursor review |
…full clear / wipe-rebuild)
|
@greptile |
|
@cursor review |
…send on a shrink)
|
@greptile |
|
@cursor review |
…rn the dedup threshold
|
@greptile |
|
@cursor review |
…tifyTableRowUsage
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b734f34. Configure here.
| currentRowCount: params.currentRowCount, | ||
| addedRows: params.addedRows, | ||
| limit, | ||
| }) |
There was a problem hiding this comment.
Table emails before commit
Medium Severity
notifyTableRowUsage runs inside assertRowCapacity as soon as the capacity check passes, before callers finish their insert transaction. If a later validation or DB step rolls back, threshold emails can still send and the atomic claim can advance limit_notifications even though no rows were added.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit b734f34. Configure here.
|
@greptile |
|
@cursor review |


Summary
lib/billing/upgrade-reasons.ts) — the source of truth for the language shown when a usage limit routes a user to the upgrade page. The same copy drives both the upgrade-page header and the threshold emails so they never drift.?reason=(nuqs) and swaps its header ("Upgrade to scale your tables", "…with your teammates", etc.); generic header when absent.buildUpgradeHref(workspaceId, reason): credits chip (credits), teammates (seats), tables row-limit toast (tables), file-upload storage error (storage, via a shareduseLimitUpgradeToast). Generic "Explore plans" links (billing settings, deploy gate) route through the same helper without a reason.LimitThresholdEmail. Dedup is a race-free atomic claim (single conditionalUPDATE … WHERE current < desired RETURNINGagainst a newlimit_notificationsjsonb column onuser_stats/organization, migration0248), with hysteresis re-arm below 70%. One sharedmaybeNotifyLimitresolves user vs. org scope for both call sites./workspace?billing=upgrade, which redirects to home and drops the param). Re-pointed to the live upgrade/billing-settings routes.Type of Change
Notes
LimitCategoryincludesseats) is ready if the seat model changes.getEmailPreferences+billingUsageNotificationsEnabled) and are best-effort/fire-and-forget so they never block a mutation.Testing
upgrade-reasons.test.ts(4) andlimit-notifications.test.ts(9 — claim win/lose, dead band, re-arm, opt-outs, billing-disabled). Existing logger/tables suites green (60 tests total).bun run check:api-validation,bun run check:react-query, typecheck, and biome all pass.Checklist