DEV Community

Pytagotech
Pytagotech

Posted on

Approval Workflows Are State Machines

Approval workflows often look simple in conversation.

"User submits a request, manager approves it, then finance processes it."

In real software, that sentence hides a state machine.

If the states are not clear, the workflow will become hard to test and hard to support.

Start with states, not buttons

A common mistake is designing the buttons first:

  • Submit
  • Approve
  • Reject
  • Revise
  • Cancel
  • Process

Buttons are actions. They should move the request between states.

The states might be:

  • draft
  • submitted
  • under_review
  • revision_requested
  • approved
  • rejected
  • cancelled
  • processed

The exact names depend on the business, but the principle is stable.

Every action should have a valid source state and target state.

Invalid transitions matter

The system should know what is not allowed.

For example:

  • a rejected request cannot be approved without reopening it
  • a processed request cannot be edited directly
  • a draft request should not appear in manager approval
  • a cancelled request should not trigger finance work
  • a revision request should return to the original submitter

Writing these rules explicitly reduces bugs.

It also makes the admin interface easier to explain.

Audit logs are not optional for serious approvals

Approval workflows need history.

At minimum, store:

  • who performed the action
  • previous state
  • next state
  • timestamp
  • note or reason
  • related attachment if needed

This helps when someone asks:

"Why was this approved?"

Or:

"Who requested the revision?"

Without a log, the team goes back to chat screenshots.

Notifications should follow state changes

Notifications are often easier when they are tied to state transitions.

Examples:

  • submitted -> notify manager
  • revision_requested -> notify submitter
  • approved -> notify finance
  • rejected -> notify submitter
  • processed -> notify requester

This is cleaner than scattering notification logic across random button handlers.

A simple test table helps

For each state, write:

Current state Allowed action Next state Actor
draft submit submitted requester
submitted approve approved manager
submitted reject rejected manager
submitted request revision revision_requested manager
revision_requested resubmit submitted requester

This table becomes a practical tool for product, engineering, QA, and support.

Approval workflows are business logic.

Treating them as state machines makes that logic visible.

Top comments (0)