Engineering Notes · Product engineering · October 2026
Separating payment, access and progress in assessment software
While building Cebras, I had to distinguish between three questions that sound related but need different answers: Has someone paid? Can they access an assessment? How far have they progressed?
The difficult part isn't displaying a questionnaire. It's keeping those answers consistent across checkout, login and a journey someone may resume days later. Here's how I approach that boundary and the trade-offs it introduces.
One user, three different questions
Consider someone who has completed onboarding, paid for an assessment, but hasn't started it.
They have an account and access, but no journey progress. A single flag such as
isActive would be ambiguous: active in which sense?
The product separates onboarding, entitlement and progress so they can change independently. That distinction determines which screens someone sees and which actions the backend allows.
These are illustrative states, not a reproduction of the production data model. Explicit states mean more conditions to manage, but they also make the reasons behind an access decision easier to understand.
Why the browser return cannot grant access
Checkout adds an asynchronous boundary. A user may finish paying and close the tab before the browser returns to Cebras. Conversely, loading a success URL is not evidence that the payment provider has confirmed a purchase.
I connected the purchase flow to backend confirmation: the payment event is processed before assessment access is granted. The redirect brings the person back into the product, but it isn't the authority for changing their entitlement.
This choice brings its own engineering questions. What does the user see if confirmation arrives late? What should happen when a notification is repeated? A robust flow needs to account for both rather than assuming that browser navigation and payment processing always finish together.
What separating those states changes
Once access and progress are independent, an assessment can distinguish someone who has paid but not started from someone who is midway through a journey. That also gives frontend views and backend authorization rules a clearer shared vocabulary.
The separation also makes edge cases easier to describe. For example, a returning user can be entitled to start an assessment without having made any progress. A payment event may arrive after checkout has closed, or the same notification may be delivered twice. Each situation needs a different expected response.
| Scenario | Expected behavior |
|---|---|
| Checkout opened, payment not confirmed | No new assessment entitlement |
| Payment confirmed, journey not started | Assessment available to start |
| Journey interrupted after starting | Existing progress remains distinguishable from access |
| Payment notification delivered again | No duplicate entitlement granted |
This matrix describes behaviors worth validating, not a claim that every edge case is already covered by automated tests.
The broader lesson is to model the questions the business actually asks. A payment, permission and progress indicator may appear together on one screen, but keeping their meaning separate makes changes easier to implement, debug and explain.