Start here. This is the direct spoken answer to practice first.
Why this question matters
Many backend products are state machines hidden behind status fields. Explicit states, guarded transitions, concurrency rules, history, and repair paths keep business behavior from scattering across controllers and jobs.
I would model the workflow with explicit states and allowed transitions. Each transition has a command, actor, guard rules, timestamp, and optional reason. The API exposes operations such as submit, approve, reject, cancel, or reopen rather than letting clients set arbitrary status values. The database stores the current state and a transition history so the system can explain how it got there.