An order in an online shop is not just a row in a table; it moves through a lifecycle. It is created, waits for payment, gets packed and shipped, and may be cancelled, returned or refunded. This UML state machine diagram lists every state an order can be in and every legal move between them.
Anything not drawn is not allowed. That is the point: you cannot ship an unpaid order or refund one twice.
1. The Diagram
The filled dot is the start. A new order is Created; when the customer submits checkout it moves to AwaitingPayment.
A declined card loops back to the same state (yellow self transition) while the guard [attempts < 3] holds.
If no payment arrives within 30 minutes, the time event after(30 min) fires, reserved stock is released, and the order is Cancelled.
A successful authorization moves the order to Paid. It can still be cancelled while the guard [not shipped] is true, and the effect / refund() runs on the way.
Fulfilment is a composite state with its own small machine: Picking, Packed, Shipped. Composite states keep the top level readable.
When the carrier confirms delivery the order is Delivered and may end there. Within 30 days the customer can request a return; once the item is received the refund runs and the order ends as Refunded.
2. How to Read It
Transition labels follow one pattern: event [guard] / effect. All three parts are optional. Colours here are only emphasis: green for the happy path, yellow for retries and returns, red for cancellation.
3. Variant: Orthogonal Regions
Some shops ship before payment clears, for example on invoice terms. Then payment and shipping are independent. UML handles this with orthogonal regions: one composite state split by a dashed line, each region with its own start and end. The order is in one state of each region at once, such as Paid and NotShipped. This avoids drawing every combination as a separate state.
4. Pros and Cons
Pros
Makes illegal transitions obvious: if there is no arrow, the code must reject the event.
Translates directly to a status enum plus a transition table, or to libraries such as XState or Python transitions.
Gives testers a ready checklist: one test per arrow, one per guard.
Time events and guards capture business rules (30-minute hold, 30-day return window) in one place.
Composite states and regions keep big lifecycles readable.
Cons
Covers one object only; it does not show which service sends each event.
Easy to forget error states such as payment provider timeouts.
Large machines with many guards are hard to lay out by hand.
Teams sometimes draw it once and never update it when statuses change.
5. When to Use It
Use it when
An entity has a status column and rules about how it changes.
You are designing workflows, protocols, UI wizards or retry logic.
Bugs come from objects doing things in the wrong state.
Skip it when
You care about the order of calls between services: use a sequence diagram.
The flow involves several people and systems: use an activity diagram with swimlanes.
The object has only two states; a sentence is enough.