Skip to content

Settings: show price before PayPal (subscribe + resize) + merge size/subscription sections #27

Description

@ClaydeCode

UX improvements for the subscription/resize area of the shard Settings page (web-terminal). Most are polish, except item 2's subscribe-side price display, which is a public-launch blocker (compliance — see below). PayPal billing went live in production 2026-06-23; these items surfaced in the live test.

1. Merge the Size and Subscription sections

The VM-size controls and the billing/subscription card are currently separate sections, but they're tightly coupled — a resize on a subscribed shard is a billing change (PayPal revise + new monthly price). Presenting them apart is confusing. Combine them so size selection and its billing consequence live together.

2. Show the monthly price in the shard UI before committing — both initial subscribe AND resize

Today the price is never shown in our UI — it first appears on PayPal's own screen, for both the initial subscribe and a resize/upgrade. Surfaced in the 2026-06-23 live production test: no price tag on subscribe or on upgrade; the user only saw the amount once PayPal rendered it.

Show the resulting monthly gross price in our UI before the buyer is sent to PayPal:

  • Subscribe: show the monthly price for the selected size on the subscription card, before the subscribe button.
  • Resize: show the new monthly price and the delta vs current, before confirming.

computeMonthlyPrice(vm_size, volume_size_gb) already exists client-side (mirrors the controller's compute_price), so the projected price for a candidate size can be shown inline in both flows.

⚠️ Compliance, not just polish (subscribe case). For B2C / German consumer law the price must be clearly visible before purchase. "Price only appears on PayPal's screen" is arguably non-compliant for public launch — treat the subscribe-side price display as a launch blocker, distinct from the resize polish.

Notes

  • Show gross (incl. 19% VAT). Confirm pricing.js carries the ×1.19 from controller #298 — if the mirror lagged, the preview would display net and disagree with the actual charge (the lockstep risk flagged in controller #296).
  • Keep the controller as price source of truth; the client-side pricing.js is a mirror kept in lockstep — fine for a preview, but the authoritative charge is still server-computed.
  • Relates to the in-window PayPal subscribe work (#265) and the typed-client follow-up (Generate a typed API client from the controller OpenAPI (single source of truth) #24).

3. Fix the PayPal revise button placement/styling

The PayPal SDK button that renders when a new size is selected (active subscription, renderResizeButton in Settings.vue) just pops in and is awkwardly placed — it isn't laid out cleanly within the size controls. Give it a deliberate position/spacing (and ideally fold it into the merged section from item 1).

4. Standby/interstitial screen after resize approval

After the buyer approves the resize, the shard restarts to apply the new VM size. The UI should route to a standby/interstitial screen that polls the shard until the restart completes, then returns to Settings — instead of leaving the user on a busy Settings page. This existed before (the immediate/unsubscribed path still does router.replace('/restart')); the subscribed SDK onApprove path currently only sets waitingForRestart + polls in place. Reuse the restart/interstitial screen for the subscribed path too.

Both surfaced verifying the in-window SDK resize (controller #294, web-terminal #29) in sandbox — resize works; these are polish.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions