Skip to content

Document Approval

This example demonstrates a document approval workflow with submission, review, revisions, and multi-level approvals.

Complete Flow

flow
machine: @document

scenario: submission

  given:
    @author is logged in
    document is created with title "Q4 Report"

  on :submit from @author (api)
    document moves to #pending_review
    notify available reviewers

    expect:
      = document is in #pending_review

  on :claim from @reviewer
    document moves to #in_review
    $reviewer: string becomes @reviewer.id

    expect:
      = document is in #in_review

  expect:
    = document is ready for review

scenario: review

  given:
    document is in #in_review
    @reviewer has claimed document

  on :approve from @reviewer (api)
    ? document meets standards
      document moves to #approved
      $approvals: number increases by 1

      ? $approvals equals $required_approvals
        document moves to #published
        emit :published to @author

    expect:
      = $approvals increased

  on :request_changes from @reviewer (api)
    document moves to #revision
    emit :changes_requested to @author
      with:
        | comments | $review_comments |

    expect:
      = document is in #revision

  on :resubmit from @author (api)
    document moves to #pending_review
    $version: number increases by 1
    notify @reviewer

    expect:
      = document is in #pending_review
      = $version increased

  expect:
    = document workflow completed

Multi-Level Approval

For documents requiring multiple approvers:

flow
machine: @document

scenario: multi-level approval

  given:
    document is created
    $required_approvals: number is 3
    $approvals: number is 0

  on :submit from @author (api)
    document moves to #pending_review
    emit :review_request to @reviewers

  on :approve from @reviewer
    ? document is in #pending_review
      ? not already_approved_by($reviewer)
        $approvals increases by 1
        $approved_by adds @reviewer.id

        ? $approvals >= $required_approvals
          document moves to #fully_approved
          emit :document_approved to @author

    expect:
      = $approvals increased

  on :reject from @reviewer
    document moves to #rejected
    $rejection_reason becomes $reason
    emit :document_rejected to @author
      with:
        | reviewer | @reviewer.id     |
        | reason   | $rejection_reason |

  expect:
    = approval process completed

Approval with Hierarchy

Documents that need different levels of approval:

flow
machine: @document

scenario: hierarchical approval

  given:
    document is created with type "contract"
    $contract_value: number is 50000

  on :submit from @author (api)
    document moves to #awaiting_manager

  on :approve from @manager (api)
    ? $contract_value < 10000
      document moves to #approved
      emit :approved to @author

    ? $contract_value >= 10000
    ? $contract_value < 100000
      document moves to #awaiting_director
      emit :review_request to @director

    ? $contract_value >= 100000
      document moves to #awaiting_vp
      emit :review_request to @vp

  on :approve from @director (api)
    ? document is in #awaiting_director
      ? $contract_value < 100000
        document moves to #approved
        emit :approved to @author

      ? $contract_value >= 100000
        document moves to #awaiting_vp
        emit :review_request to @vp

  on :approve from @vp (api)
    ? document is in #awaiting_vp
      document moves to #approved
      emit :approved to @author

  on :reject from @manager (api)
    document moves to #rejected

  on :reject from @director (api)
    document moves to #rejected

  on :reject from @vp (api)
    document moves to #rejected

  expect:
    = document has been processed

State Diagram

@document#draft:submit#pending_review:claim#in_review:approve:request_changes:reject#approved#revision#rejected:resubmit[all approvals]#published

Lane Diagram

@author@reviewer@system:submitnotified:claimreviews:request_changesrevises:resubmit:approve:published

Testing Scenarios

Simple Approval

flow
scenario: document approved on first review

  given:
    @author is logged in
    document is created

  on :submit from @author (api)
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on :approve from @reviewer (api)
    $approvals becomes 1
    document moves to #published

  expect:
    = document is in #published
    = @author received :published

Revision Cycle

flow
scenario: document requires revision

  given:
    @author is logged in
    document is created
    $version: number is 1

  on :submit from @author (api)
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on :request_changes from @reviewer (api)
    document moves to #revision

  on :resubmit from @author (api)
    $version becomes 2
    document moves to #pending_review

  on :approve from @reviewer (api)
    document moves to #published

  expect:
    = document is in #published
    = $version equals 2

Multi-Approver Flow

flow
scenario: three approvals required

  given:
    $required_approvals: number is 3
    $approvals: number is 0

  on :submit from @author (api)
    document moves to #pending_review

  on :approve from @reviewer_1 (api)
    $approvals becomes 1

  on :approve from @reviewer_2 (api)
    $approvals becomes 2

  on :approve from @reviewer_3 (api)
    $approvals becomes 3
    document moves to #fully_approved

  expect:
    = document is in #fully_approved
    = $approvals equals 3

Rejection

flow
scenario: document rejected

  given:
    @author is logged in
    document is created

  on :submit from @author (api)
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on :reject from @reviewer (api)
    $rejection_reason becomes "Does not meet standards"
    document moves to #rejected

  expect:
    = document is in #rejected
    = @author received :document_rejected

Released under the MIT License.