ReviewOS

stacks/analyticshq

There is a way to start paying and no way to stop

#46
Open glennmichael123 opened this 9 days ago ·
9 days ago

Checkout works. Nothing else does.

There is no cancel, no plan change, no billing portal, no payment-method update, no invoice or receipt history. resources/views/account.stx shows a Plan card whose button links to /pricing in both states — "Upgrade to Pro" when free, "Manage plan" when paying, and the second one is a lie: there is nothing to manage there.

Now that the paywall is real (invitations are Pro-gated), this is the next thing a customer will reach for, and the first thing they will reach for in anger.

Why it matters beyond politeness

  • A customer who cannot find a cancel button charges back instead. A chargeback costs the fee plus the dispute, and enough of them threaten the Stripe account itself.
  • Consumer rules in several jurisdictions require cancellation to be as easy as signup. Ours is a checkout button versus an email to support.
  • "Where is my invoice" is unanswerable today, and it is the single most common billing request from any business customer.

What exists to build on

storage/framework/defaults/app/Actions/Payment/ ships 21 actions — CancelSubscriptionAction, UpdateSubscriptionAction, FetchActiveSubscriptionAction, FetchTransactionHistoryAction, CreateSetupIntentAction, FetchPaymentMethodsAction and more — plus views/dashboard/settings/billing.stx and a set of Billing components.

None of it is mounted. routes/auth.ts:30-38 documents why: this app mounts no framework default routes, only actions resolved by string. So adopting them is a matter of declaring the routes, not writing the logic.

Payment also exposes cancelSubscription, changeSubscription and getInvoices directly.

Suggested scope for a first pass

  1. Cancel, at period end rather than immediately — the customer keeps what they paid for, and userIsPro() already handles this correctly: provider_status stays active until the period actually ends, and ends_at is deliberately not consulted.
  2. Invoice/receipt list from Payment.getInvoices.
  3. Make the account page's "Manage plan" button go somewhere real.

Payment-method update and plan switching can follow. A Stripe billing portal session would deliver most of this in one endpoint if we would rather not own the UI.

Cancellation should let the webhook write the local row rather than writing it here — see how customer.subscription.deleted already syncs. Writing both sides risks a local/Stripe split if the process dies between them.

Sign in to comment on this issue.