Problem statement
Design the object model and core APIs for the lifecycle state machine of a customer order, from creation through payment, fulfilment, cancellation, and refund, for a single commerce service.
Operating context. An order moves through states (created, payment-pending, paid, fulfilling, shipped, delivered, cancelled, refunded) driven by events (pay, authorize-failed, reserve-stock, ship, deliver, cancel, refund). Each transition may have a guard (a precondition such as payment authorized) and an action (a side effect such as reserving stock or capturing payment) that runs as it commits. Only declared transitions are legal from a given state. Events can arrive duplicated or out of order and must be handled idempotently, and two events for one order may race.
Out of scope. The concrete payment gateway and inventory system (place them behind ports/interfaces), the customer UI, the persistence layer, and notification delivery.
What to produce. The state model (states, the transition table keyed on state and event), the guard/action abstraction, the event-handling API, and the transition history. Be explicit about: how an undeclared transition is rejected rather than crashing, how a duplicate or out-of-order event is made idempotent, how two concurrent events for one order are serialized, and how adding a new state is a declarative change rather than new branches.
Functional requirements
- Advance an order between states only along explicitly declared transitions, rejecting any undeclared one.
- Run a transition's guard before it fires and its action as it commits, rolling back cleanly if the action fails.
- Handle a duplicate or out-of-order event idempotently so a replayed message does not double-apply an effect.
- Expose the set of actions currently permitted on an order given its state.
- Record the transition history so the path an order took is reconstructable.
Non-functional requirements
- A transition lookup is O(1) on the (state, event) pair, independent of the number of states.
- Adding a state or transition is declarative data, not new branches in the event handler (open/closed).
- Concurrent events on one order serialize so the machine never lands in an inconsistent state.
- External effects (payment, inventory) sit behind ports, so the machine is testable with fakes and no network.
- Every transition is total and side-effect-free until its guard passes, so a rejected event leaves state unchanged.
- The machine is deterministic under an injected clock and event source.
Topics
- System Design LLD
- Commerce Orders
- Patterns State
- Concurrency Idempotency
- Oop Solid