Borrow Lifecycle State Machine
Borrowing an item involves two users (Lender and Borrower), physical handoffs, and verification steps. I modeled this flow as an explicit Finite State Machine.
Role-Based Transition Rules
To prevent illegal state jumps or unauthorized status changes, every transition is validated against the user's role:
| Transition | From State | To State | Allowed Role | Trigger Action |
|---|---|---|---|---|
| Accept | REQUESTED | ACCEPTED | Lender | accept() |
| Reject | REQUESTED | REJECTED | Lender | reject() |
| Cancel | REQUESTED / ACCEPTED | CANCELLED | Borrower / Lender | cancel() |
| Confirm Pickup | ACCEPTED | BORROWED | Lender | confirmPickup() |
| Confirm Return | BORROWED | RETURNED | Lender | confirmReturn() |
Automated Transitions
There are also automated system transitions! If a REQUESTED borrow isn't accepted within a few days, a scheduled cron job transitions it to EXPIRED. Similarly, an active BORROWED state moves to OVERDUE if the item isn't returned by the expected date.
Why an Explicit State Machine?
- Zero Invalid States: It is impossible for an item to jump directly from
REQUESTEDtoRETURNED. - Role Verification: Attempting an action without the correct role (e.g. Borrower trying to accept their own request) throws an immediate
ForbiddenException. - Auditability: Every state transition generates a timestamped audit log entry and publishes an event for user notifications.