fix(billing): point self-hosted upgrade CTAs at the hosted app - #6003
fix(billing): point self-hosted upgrade CTAs at the hosted app#6003TheodoreSpeaks wants to merge 1 commit into
Conversation
Self-hosted Chat bills against the sim.ai account behind COPILOT_API_KEY, but its 402 upgrade card linked to local billing settings that a self-hosted deployment does not have. Point those CTAs at the hosted app instead, and drop the local workspace-role gate that could hide the CTA from the only person able to act on it. Adds /upgrade, an account-scoped entry for callers that cannot know a workspace id. It delegates to /workspace?redirect=upgrade rather than re-deriving workspace resolution, inheriting local recency, stale-session recovery, and the no-workspace creation policy.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Usage upgrade cards on self-hosted now open hosted URLs ( A new account-scoped Reviewed by Cursor Bugbot for commit e1ac4a8. Bugbot is set up for automated code reviews on this repo. Configure here. |
| : data.action === 'upgrade_plan' | ||
| ? buildHostedUpgradeUrl() | ||
| : HOSTED_BILLING_SETTINGS_URL |
There was a problem hiding this comment.
Upgrade CTA drops reason param
On self-hosted, the upgrade_plan CTA calls buildHostedUpgradeUrl() without data.reason, so the hosted /upgrade page never receives the reason query used for limit-specific header copy; other upgrade paths forward reason through buildUpgradeHref / buildHostedUpgradeUrl.
| : data.action === 'upgrade_plan' | |
| ? buildHostedUpgradeUrl() | |
| : HOSTED_BILLING_SETTINGS_URL | |
| : data.action === 'upgrade_plan' | |
| ? buildHostedUpgradeUrl(isUpgradeReason(data.reason) ? data.reason : undefined) | |
| : HOSTED_BILLING_SETTINGS_URL |
Greptile SummaryPoints self-hosted usage-upgrade CTAs at the hosted app, adds an account-scoped
Confidence Score: 4/5Safe to merge from a blocking-defect perspective; only a small self-hosted CTA UX gap remains (upgrade reason not forwarded). Redirect chain, login callback encoding, billing settings path, and Next external redirect behavior check out; the remaining issue is that self-hosted Upgrade Plan links drop the tag reason query used for header copy. Files Needing Attention: apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx
|
| Filename | Overview |
|---|---|
| apps/sim/app/upgrade/page.tsx | New account-scoped upgrade entry preserves reason and login callback, then delegates workspace resolution to /workspace. |
| apps/sim/app/workspace/[workspaceId]/upgrade/page.tsx | Server-side redirects for self-hosted (external hosted upgrade) and billing-disabled (home) before mounting Upgrade. |
| apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx | Self-hosted CTAs link off-site and skip local billing roles; upgrade_plan omits reason on the hosted URL. |
| apps/sim/app/workspace/page.tsx | Handles ?redirect=upgrade after workspace selection and forwards optional reason into buildUpgradeHref. |
| apps/sim/lib/billing/upgrade-reasons.ts | Adds SITE_URL-based hosted upgrade and billing settings URL helpers with tests. |
Sequence Diagram
sequenceDiagram
participant SH as Self-hosted UI
participant Local as Local Next app
participant Hosted as www.sim.ai
Note over SH: usage_upgrade CTA
SH->>Hosted: open /upgrade or /account/settings/billing
Note over Local: /workspace/.../upgrade when !isHosted
Local->>Hosted: redirect(buildHostedUpgradeUrl)
Note over Hosted: /upgrade entry
Hosted->>Hosted: "login callback or /workspace?redirect=upgrade"
Hosted->>Hosted: resolve workspace then plan picker
Reviews (1): Last reviewed commit: "fix(billing): point self-hosted upgrade ..." | Re-trigger Greptile
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e1ac4a8. Configure here.
| ? getSettingsHref({ section: 'billing' }) | ||
| : data.action === 'upgrade_plan' | ||
| ? buildHostedUpgradeUrl() | ||
| : HOSTED_BILLING_SETTINGS_URL |
There was a problem hiding this comment.
Billing CTA drops login destination
Medium Severity
Self-hosted increase_limit CTAs open hosted /account/settings/billing directly. That route sends signed-out visitors to /login with no callbackUrl, so after auth they land on the default workspace instead of billing — unlike the /upgrade path, which was written to preserve intent.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit e1ac4a8. Configure here.


Summary
COPILOT_API_KEY, but the 402 upgrade card linked to local billing settings a self-hosted deployment doesn't have. Those CTAs now point at the hosted app, and no longer apply the local workspace-role gate — which could hide the CTA from the only person able to act on it, since local roles say nothing about the hosted account./upgrade, an account-scoped entry for callers that can't know a workspace id (a self-hosted deployment, an email). It delegates to/workspace?redirect=upgradeinstead of re-deriving workspace resolution, so it inherits local recency, stale-session recovery, and the no-workspace creation policy./workspace/[workspaceId]/upgraderesolves the self-hosted and billing-disabled cases in the Server Component. Both are build-time constants, so the old client-effect redirect made every self-hosted visitor mount the full plan-picker graph just to navigate away.SquareArrowUpRight+ anaria-label, so a self-hoster gets a signal they're leaving their deployment.Type of Change
Testing
type-check19/19, all 11 CI audits pass, 42 tests green across the touched files. Redirect chain verification in progress locally.Checklist