Flow
The steps I built and the check I would put on each
1Button carries the plan
Each pricing button should open the login page with the right plan in the address.
2Login page saves it
Unknown plans should be ignored, and the cookie should leave with the redirect.
3Return to the small page
A sign-in with no cookie should still end on the dashboard.
4Read once, delete
A second sign-in right after a paid one should not go to checkout.
5Checkout retries, then stops
If checkout keeps failing, the retries should end and the billing button should appear.
6Locked data, called directly
Unknown so far: whether a free account gets refused. That is the next thing I want to try.
Both buttons on my pricing page went to the same place. The free one and the paid one both linked to the front of the app, and after sign-in everyone landed on the home page. So you could pick the paid plan, sign in, and end up on the free dashboard as if you'd never picked anything. The app never got the choice at all.
That was my mistake. All of this is from reading the change I made, which came with no tests.
Getting a choice through someone else's front door
Sign-in sends the browser to an outside login service and back. Whatever was in the address on the way out is gone when it returns. So you have to save the choice yourself before the browser leaves.
The flow now works in four steps:
- Each pricing button opens the app's login page with the plan in the address, including an explicit free.
- The login page accepts only the plans it knows and saves the choice in a short-lived cookie that page scripts can't read. It sets that cookie on the same response that sends the browser off to sign in.
- After sign-in, the browser comes back to a small new page instead of the home page.
- That page reads the cookie, deletes it every time, and sends a paid choice to checkout and everyone else to the dashboard.
The cookie doesn't need to be signed, because the only thing it does is pick a page. Faking it gets you a checkout screen, which I'm guessing you could reach from the billing page anyway.
The checkout page that has to wait for the account
A new account may not be fully set up the moment sign-in ends. So the checkout page tries to start checkout, waits a couple of seconds if that fails, and tries again a few times. Then it gives up and shows a button to the billing page.
My problem with it is that it can't tell "not ready yet" from "broken." If the price setting is missing, it still makes every new paid user wait through every retry. I want the server to say "not ready" plainly and the page to retry only then. I haven't built that.
Paid features stopped pretending not to exist
Paid areas used to be hidden behind feature switches. Now they show up in the menu with a paid badge, and free accounts get an upgrade prompt instead of the page. The billing page lost its flag too, since that's where upgrades happen.
That prompt only changes what the page shows. I still don't know if the data behind those pages checks the plan, so my next step is to call it as a free account and see what comes back.