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
    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
    ? 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
    document moves to #revision
    emit :changes_requested to @author
      with:
        | comments | $review_comments |

    expect:
      = document is in #revision

  on> :resubmit from @author
    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
    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
    document moves to #awaiting_manager

  on> :approve from @manager
    ? $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
    ? 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
    ? document is in #awaiting_vp
      document moves to #approved
      emit :approved to @author

  on> :reject from @manager
    document moves to #rejected

  on> :reject from @director
    document moves to #rejected

  on> :reject from @vp
    document moves to #rejected

  expect:
    = document has been processed

State Diagram

                          @document

┌─────────────────────────────────────────────────────────────────────┐
│                                                                     │
│  ┌─────────┐   :submit     ┌────────────────┐                      │
│  │ #draft  │──────────────>│ #pending_review│                      │
│  └─────────┘               └───────┬────────┘                      │
│       ▲                            │                               │
│       │                       :claim                               │
│       │                            │                               │
│       │                            ▼                               │
│       │                    ┌─────────────┐                         │
│       │                    │ #in_review  │                         │
│       │                    └──────┬──────┘                         │
│       │                           │                                │
│       │            ┌──────────────┼──────────────┐                 │
│       │            │              │              │                 │
│       │      :approve      :request_changes  :reject               │
│       │            │              │              │                 │
│       │            ▼              ▼              ▼                 │
│       │     ┌───────────┐  ┌───────────┐  ┌───────────┐           │
│       │     │ #approved │  │ #revision │  │ #rejected │           │
│       │     └─────┬─────┘  └─────┬─────┘  └───────────┘           │
│       │           │              │                                 │
│       │           │         :resubmit                              │
│       │           │              │                                 │
│       │           │              └─────────────────────────────┐   │
│       │           │                                            │   │
│       │           │ [all approvals]                            │   │
│       │           │                                            │   │
│       │           ▼                                            │   │
│       │    ┌─────────────┐                                     │   │
│       │    │ #published  │                                     │   │
│       │    └─────────────┘                                     │   │
│       │                                                        │   │
│       └────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Lane Diagram

┌───────────┬────────────┬────────────┐
│  @author  │ @reviewer  │  @system   │
├───────────┼────────────┼────────────┤
│           │            │            │
│ :submit   │            │            │
│ ──────────┼──>         │            │
│           │            │            │
│           │ notified   │            │
│           │            │            │
│           │ :claim     │            │
│           │ ──────────>│            │
│           │            │            │
│           │ reviews    │            │
│           │            │            │
│           │ :request_  │            │
│           │ changes    │            │
│ <─────────┼────────────│            │
│           │            │            │
│ revises   │            │            │
│           │            │            │
│ :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
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on> :approve from @reviewer
    $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
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on> :request_changes from @reviewer
    document moves to #revision

  on> :resubmit from @author
    $version becomes 2
    document moves to #pending_review

  on> :approve from @reviewer
    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
    document moves to #pending_review

  on> :approve from @reviewer_1
    $approvals becomes 1

  on> :approve from @reviewer_2
    $approvals becomes 2

  on> :approve from @reviewer_3
    $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
    document moves to #pending_review

  on :claim from @reviewer
    document moves to #in_review

  on> :reject from @reviewer
    $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.