States, statuses, and option sets
How to keep lifecycle rules out of scattered page conditions and workflow branches.
You add a field called status. At first it only controls a label in the UI. Then the client asks for a button to show only when the thing is ready, a notification to send only when it is approved, and a dashboard to count what is overdue.
Status represents where the thing is in the business process, which action is allowed next, and which parts of the app should treat it differently.
Status is a rule
Most business objects have a lifecycle. An invoice can be draft, sent, paid, or void. A booking can be requested, confirmed, cancelled, or complete. An application can be submitted, reviewing, accepted, or rejected.
Those values decide how the app behaves. They control which buttons appear, which workflows are valid, which records appear in searches, which notifications send, and what dashboards count. If the status field is loose, every one of those places has to compensate.
Text is too loose
A text field is usually the wrong place to store lifecycle status. Bubble will let you save pending, Pending,in progress, and In Progress as different values. Searches and conditions then depend on exact spelling.
A search for applications where status = Reviewing misses records saved as reviewing. A button condition has to check more than one text value. The fix is to stop using text for fixed lifecycle states.
Option sets
Use an option set when the statuses are fixed values in the app's logic. An Invoice Status option set might have Draft,Sent, Paid, and Void. Every workflow, condition, search, and reusable element now points to the same values.
This is the right fit when the statuses are not created by users, do not need permissions, and are not expected to change per client account. The statuses are part of how the app works.
When status needs a data type
Some statuses look fixed until a user wants to configure them. A CRM pipeline stage in a SaaS app might begin as an option set: Lead, Qualified, Proposal, Won, Lost. Then, we might want to support renaming stages, reordering them, restricting by team, or some other variant.
In that case, Pipeline Stage needs to be a data type, not an option set. Use a Pipeline Stage data type, and letDeal point to the current stage.
An option set works when every app uses the same values. A data type works when the values belong to an account, team, or user configuration. Once the user can edit the available stages, the stages need records in the database.
Allowed transitions
After you choose where the status lives, decide how it is allowed to change. Lifecycle transitions should happen through their own dedicated workflows. Do not set the status field directly from whatever workflow happens to be running, such as a button workflow, a save workflow, or a page condition that also changes data.
For example, a Finalize invoice workflow can take an invoice in any non-finalized state, validate the required fields, and mark it asFinalized. A Mark invoice paid workflow can require the invoice to be Finalized or Overdue, then set it to Paid. A button should call the workflow; it should not make changes to the invoice and set status = Paid itself.
This keeps the transition checks in one place. When the rule changes, you update the workflow that owns the transition instead of hunting for repeated status updates across pages.