Billing awareness: show when a plan renews, ends or turns into a charge; promo through sign-up - #817
Merged
Conversation
…to a charge
The app only knew a paid licence as 'active'. A card-trial customer never saw
when the first charge comes, a customer who cancelled never saw when the plan
ends, and cancelling meant finding the Stripe portal home behind a button
called 'Manage subscription & billing'.
- Licence verification (cloud) now asks the licence site for the subscription's
state (status, cancelling + end date, trial end, renewal date, price) and
stores it in a new nullable licenses.billing column (additive migration).
/api/license/status returns it.
- POST /api/license/refresh (cloud, admin, throttled once a minute per
workspace) re-verifies right away; the licence page calls it on load, so a
change made in the billing portal or Checkout shows immediately.
- Settings -> License shows one plain sentence: 'Free trial until X, then
EUR 49/month', 'Your subscription is cancelled and ends on X', 'Renews on X'
or 'Your last payment failed'. The main button becomes 'Keep my plan' or
'Update payment method' when that is what is needed, and a labelled 'Cancel
subscription' opens Stripe's cancellation page directly (billing-portal
flow=cancel).
- A SubscriptionBanner tells admins above the app: a failed payment (always),
a cancelled plan in its last 7 days, a card trial in its last 3 days.
- Settings nav describes the licence page as 'Plan, billing, subscription'.
Promotion code through sign-up: a code from the pricing page (?promo=) is kept
beside the plan intent, shown on /start-trial ('Code START30 will be applied at
checkout') and sent with the checkout link, which passes it to the licence site.
Tests: billing parsing/storage/refresh throttle, promo pass-through (backend);
billing helpers, licence page states, banner, promo flow (e2e). Full backend
suite and all 83 e2e pass.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Why
Second wave of the Cloud funnel audit (first wave: #815). The app knew a paid licence only as "active": a card-trial customer never saw when the first charge comes, a customer who cancelled never saw when the plan ends, and cancelling meant finding the Stripe portal home.
What
Subscription state in the app
licenses.billingcolumn (additive migration)./api/license/statusreturns it.POST /api/license/refresh(cloud, admin, once a minute per workspace): the licence page calls it on load so changes made in the portal / Checkout show immediately.flow=cancel).SubscriptionBannerfor admins: failed payment (always), cancelled plan in its last 7 days, card trial in its last 3 days.Promo through sign-up:
?promo=on the sign-up link is kept beside the plan intent, shown on/start-trialand sent with the checkout link.Depends on
Website PR (billing in
/api/license/verify,flow=cancelon/api/billing/portal,promoCodeon checkout intents). Without it the new fields are simply absent and the app behaves as before. Deploy the website first.Tests
Backend: billing parse/store/refresh throttle, promo pass-through. Frontend:
billing-awareness.spec.ts(helpers, licence page states, banner, promo flow). Full backend suite (6318) and all 83 e2e pass.