Skip to content

Billing awareness: show when a plan renews, ends or turns into a charge; promo through sign-up - #817

Merged
keysersoft merged 1 commit into
mainfrom
keysersoft/billing-awareness-followups
Oct 1, 2026
Merged

keysersoft merged 1 commit into
mainfrom
keysersoft/billing-awareness-followups

Conversation

@keysersoft

Copy link
Copy Markdown
Contributor

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

  • Cloud licence verification asks the licence site for the subscription's state (status, cancelling + end date, trial end, renewal, price) and stores it in a new nullable licenses.billing column (additive migration). /api/license/status returns 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.
  • Settings → License shows one sentence ("Free trial until X, then €49/month", "Your subscription is cancelled and ends on X", "Renews on X", "Your last payment failed"). The main button adapts (Keep my plan / Update payment method) and a labelled Cancel subscription opens Stripe's cancellation page directly (flow=cancel).
  • SubscriptionBanner for 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-trial and sent with the checkout link.

Depends on

Website PR (billing in /api/license/verify, flow=cancel on /api/billing/portal, promoCode on 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.

…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.
@keysersoft
keysersoft merged commit 7c1402e into main Oct 1, 2026
14 checks passed
@keysersoft
keysersoft deleted the keysersoft/billing-awareness-followups branch October 1, 2026 13:14
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant