mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 10:35:51 +00:00
d5bc3e3862
Stripe checkouts could not be told apart by origin: every session was stamped checkout_origin pulserelay_landing, so an upgrade started from an RBAC gate looked identical to one started from the website. Gate CTAs now stamp a closed-vocabulary source token (gate-<feature>, estate-card, or the plans-page default) onto the owned billing plan route; the plan page threads it into the purchase-start handoff, and the license server persists it on the checkout intent and stamps Stripe metadata checkout_source. Attribution is authenticated-session-only by construction. The public /pricing route and the public pricing URL never carry it, and getSelfHostedPurchaseStartUrl scrubs the parameter from forwarded query strings so a crafted website link cannot claim in-app origin. Server-side, source is validated against the same kebab vocabulary, skip-listed from the Pulse Account portal redirect exactly as feature already is, and travels only inside the handoff body. It is request-scoped and persists nothing on the install; the cancel return echoes it so a retry keeps its origin. The handoff field is omitempty because the license server decodes strictly, so source-less installs stay compatible with a server either side of the field being added. That ordering is recorded in pulse-pro OPERATIONS.md.