Skip to content

BaaS direct checkout: monthly only; gate views only on real paywalls - #839

Merged
charles-ramos merged 4 commits into
production2from
baas-upgrade-instrumentation
Oct 19, 2026
Merged

charles-ramos merged 4 commits into
production2from
baas-upgrade-instrumentation

Conversation

@alyssoncm

@alyssoncm alyssoncm commented Oct 13, 2026 •

Copy link
Copy Markdown

What

  • Monthly only in the direct checkout. Paywall checkouts open on the monthly price, with no yearly option. Plan Usage defaults back to Monthly; yearly stays one toggle away there.
  • Gate views only on real paywalls. baas_upgrade_gate_viewed fires only on paywalls the user reaches by trying the feature (logView). Always-on Overview buttons (plan badge/card, MongoDB 8, web hosting, HTTPS, compliance) log only the click.

Why

Since the paywalls went direct-to-checkout, MVP yearly ($180 today) converted 0/61 openings (Oct 6–12, Paddle export), and the Overview buttons inflated gate views on every visit.

Note

This branch is based on #835 and conflicts with production2 (#836/#837 touched UpgradeCheckout.react.js, DomainSettings.react.js and the checkout tests). The conflicts are not resolved yet; the gates added after #835 (usage limit, backup, region, etc.) still need a logView decision during the resolution.

🤖 Generated with Claude Code


Also in this PR: what Paddle reports from inside the checkout (f411bff9)

The Backend checkout only logged opened and closed, so a drop in payments couldn't tell "never saw the form" from "saw it and left" from "tried to pay and was declined". Both places that open the Paddle checkout (the paywall modal and the Plan Usage page) now log:

Event When
baas_checkout_loaded Paddle checkout.loaded
baas_payment_initiated Paddle checkout.payment.initiated, when the card is sent
baas_payment_failed Paddle checkout.payment.failed, with error_type, error_code and error_detail
baas_checkout_event everything else Paddle reports, with name set to Paddle's name (checkout.error, checkout.warning, checkout.failed, checkout.payment.selected, …)
  • Each event carries the checkout's funnel context (app_id, plan, cycle, source, gate) and checkout_id, the che_ that Paddle support asks for.
  • Each name and error code is sent once per checkout. Frame plumbing that says nothing about the buyer (ping.size, removespinner, frame.revealed) is left out.
  • No card or email data is read.
  • The logic is paddleEventToTrack in lib/upgradeEvents, tested on its own. trackPaddleEvent only logs for a checkout the page opened.
  • Same instrumentation as Containers (back4app/back4app2#1298) and the Agent (back4app/back4app-frontend#225).

Checks

  • Tests: upgradeEvents.test.js and UpgradeCheckout.test.js pass (21 tests, 5 of them new).
  • eslint is clean on the changed files except AppPlan.react.js. Its 8 errors (b4aSettings no-undef and a missing newline at the end of the file) are already on the base branch.
  • Full jest run: the same 8 suites and 4 tests fail with and without this change.
  • Not tested in a browser.

alyssoncm and others added 4 commits October 13, 2026 13:24
Paywall checkouts open on the monthly plan with no yearly option, and
Plan Usage defaults back to Monthly (yearly stays one toggle away there).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Always-on buttons (Overview plan badge and card, MongoDB 8, web hosting,
HTTPS, compliance) count only the click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Backend checkout only logged opened and closed, so a drop in payments
could not tell "never saw the form" from "saw it and left" from "tried to pay
and was declined". What Paddle shows the buyer happens inside its iframe,
which no replay records.

Both places that open the Paddle checkout, the paywall modal and the Plan
Usage page, now log:
  baas_checkout_loaded, baas_payment_initiated, baas_payment_failed (with the
  error type, code and Paddle's message), and baas_checkout_event for
  everything else Paddle reports, under Paddle's own name (checkout.error,
  checkout.warning, checkout.failed, checkout.payment.selected, ...).
Each carries the checkout's funnel context (app, plan, cycle, source, gate)
and the che_ checkout id that Paddle support asks for. Each name and error
code goes once per checkout; frame plumbing (ping.size, removespinner,
frame.revealed) stays out. No card or email data is read.

The decision is paddleEventToTrack in lib/upgradeEvents, tested on its own;
trackPaddleEvent logs it only for a checkout the page opened. Same
instrumentation as Containers (back4app2#1298) and the Agent
(back4app-frontend#225).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep this branch's monthly-only direct checkout, opt-in gate views and
Paddle event tracking on top of production2's per-plan offers. The new
contextual paywalls (DB profiler, usage banner, backup before delete,
logs retention) log their view with logView.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@charles-ramos
charles-ramos merged commit 37b9960 into production2 Oct 19, 2026
0 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants