Scenario
A Live Contract scenario is a definition of procedure as a Finite State Machine (FSM). As an FSM, the scenario can be visualized as flowchart and instantiated as a process.
A workflow consists of an orchestrated and repeatable pattern of business activity.
A scenario is composed of a set of states and actions. An action can be executed by an actors which may trigger a state change.
The scenario can be instantiated to create a process. A scenario is stateless whereas a process is stateful. Stateful means that the computer or program keeps track of the state of interaction. Stateless means that there is no record of previous interactions.
The scenario may be defined in YAML, which is better readable. The workflow service only accepts JSON, but the LTO client libraries can convert this.
Each state MAY define a default action and each action MUST define a default response. Following these defaults results in the golden flow.
Omit a default action to wait for the timeout by default.
Scenarios have a number of implicit states. Except for
:initial
, these don't need to be defined in the scenario. You may define these not the less to set things like descriptions.Initial state
The state with key
:initial
is the initial state of the FSM.Success state
The
:success
state is an end state indicating that the process has been completed successfully.The
:cancelled
state an end state indicating that the process has been cancelled by one of the actors.Failed state
The
:failed
state is an end state indicating that the process has ended because of an error or other unexpected problem.In this scenario a supplier provides a quotation for a client to accept. The process can be started either by the client or by the supplier.
If the client starts the process, the golden flow is
- 1.Client selects the supplier and describes the service he would like a quotation for
- 2.Client invites the supplier to participate in the process
- 3.Supplier uploads a quote (due date depends on
urgency
) - 4.Client accepts the quote
- 5.done
If the supplier starts the process, the golden flow is
- 1.Supplier enters the client information
- 2.Supplier uploads a quote
- 3.Supplier invites the client to participate in the process
- 4.Client accepts the quote
- 5.done
YAML
JSON
JSON (full)
schema: https://specs.letsflow.io/v0.3.0/scenario#
id: JKdf3jddfklsr834s312
title: Product quotation
description: Send a quotation requested by the client
actors:
supplier:
$ref: "https://workflow.example.com/actors/organization/schema.json#"
client:
$ref: "https://workflow.example.com/actors/individual/schema.json#"
assets:
request:
type: object
properties:
description:
type: string
urgency:
type: string
enum:
- normal
- high
- critical
quotation:
type: object
properties:
title:
type: string
url:
type: string
definitions:
request_form:
title: Quotation request form
definition:
- fields:
- type: external-select
label: Supplier
name: supplier
url: https://jsonplaceholder.typicode.com/users
optionText: name
optionValue: "{ name, email, phone }"
required: true
- type: textarea
label: Description
name: description
helptip: Which service would you like a quotation for?
- type: select
label: Urgency
name: urgency
options:
- value: normal
label: Normal
- value: high
label: High
- value: critical
label: Critical
client_form:
title: Enter client information
definition:
- fields:
- type: text
label: Name
name: name
required: true
- type: email
label: E-mail
name: email
required: true
actions:
comment:
$schema: "http://workflow.example.com/actions/comment/schema.json#"
actor: (any)
request_quotation:
$schema: "http://workflow.example.com/actions/form/schema.json#"
actor: client
title: Quote requested by client
form: !ref definitions.request_form
update:
- select: assets.request
- select: assets.supplier
transform: supplier
invite_supplier:
$schema: "http://workflow.example.com/actions/invite/schema.json#"
actor: client
invite: supplier
responses:
ok:
display: never
error:
display: always
title: Failed to invite the supplier
data: !ref response.data.message
enter_client:
$schema: "http://workflow.example.com/actions/form/schema.json#"
actor: supplier
form: !ref definitions.client_form
display: never
update:
select: actors.client
invite_client:
$schema: "http://workflow.example.com/actions/invite/schema.json#"
actor: supplier
invite: client
responses:
ok:
display: never
error:
display: always
title: Failed to invite the supplier
description: !ref response.data.message
upload:
$schema: "http://workflow.example.com/actions/upload/schema.json#"
actor: supplier
accept: application/pdf
responses:
ok:
title: Provided a quotation
update:
select: assets.quotation
error:
label: An error occurred when uploading the quotation
display: once
review:
$schema: "http://workflow.example.com/actions/review/schema.json#"
actor: client
document: !ref assets.quotation
responses:
accept:
label: Accept
title: Accepted quotation
reject:
label: Reject
title: Rejected quotation
default_response: accept
states:
(any):
transitions:
- on: comment
goto: (current)
initial:
transitions:
- on: request_quotation
goto: invite_supplier
- on: enter_client
goto: provide_quote
invite_supplier:
transitions:
- on: invite_supplier.ok
goto: wait_for_quote
- on: invite_supplier.error
goto: (failed)
invite_client:
transitions:
- on: invite_client.ok
goto: wait_for_review
wait_for_quote:
title: Prepare quotation
instructions:
supplier: !tpl "{{ assets.request.description }} ({{ assets.request.urgency }} urgency)"
transitions:
- on: upload.ok
goto: wait_for_review
- on: upload.error
goto: (current)
provide_quote:
title: Provide quotation
transitions:
- on: upload.ok
goto: wait_for_review
- on: upload.error
goto: (current)
wait_for_review:
title: Review quotation
instructions:
client: Please review and accept the quotation
supplier: Please wait for the client to review the quotation.
transitions:
- on: review.accept
transition: (success)
- on: review.reject
transition: (cancelled)
{
"$schema": "https://specs.letsflow.io/v0.2.0/scenario/schema.json#",
"id": "JKdf3jddfklsr834s312",
"title": "Product quotation",
"description": "Send a quotation requested by the client",
"actors": {
"supplier": {
"$ref": "https://specs.letsflow.io/v0.2.0/actor/schema.json#organization"
},
"client": {
"$ref": "https://specs.letsflow.io/v0.2.0/actor/schema.json#individual"
}
},
"assets": {
"request": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"urgency": {
"type": "string",
"enum": [
"normal",
"high",
"critical"
]
}
}
},
"quotation": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"url": {
"type": "string"
}
}
}
},
"definitions": {
"request_form": {
"title": "Quotation request form",
"definition": [
{
"fields": [
{
"type": "external-select",
"label": "Supplier",
"name": "supplier",
"url": "https://jsonplaceholder.typicode.com/users",
"optionText": "name",
"optionValue": "{ name, email, phone }",
"required": true
},
{
"type": "textarea",
"label": "Description",
"name": "description",
"helptip": "Which service would you like a quotation for?"
},
{
"type": "select",
"label": "Urgency",
"name": "urgency",
"options": [
{
"value": "normal",
"label": "Normal"
},
{
"value": "high",
"label": "High"
},
{
"value": "critical",
"label": "Critical"
}
]
}
]
}
]
},
"client_form": {
"title": "Enter client information",
"definition": [
{
"fields": [
{
"type": "text",
"label": "Name",
"name": "name",
"required": true
},
{
"type": "email",
"label": "E-mail",
"name": "email",
"required": true
}
]
}
]
}
},
"actions": {
"request_quotation": {
"$schema": "http://workflow.example.com/actions/form/schema.json",
"actor": "client",
"title": "Quote requested by client",
"form": { "<ref>": "definitions.request_form" },
"update": [
{
"select": "assets.request"
},
{
"select": "assets.supplier",
"transform": "supplier"
}
]
},
"invite_supplier": {
"$schema": "http://workflow.example.com/actions/invite/schema.json",
"actor": "client",
"invite": "supplier",
"responses": {
"ok": {
"display": "never"
},
"error": {
"display": "always",
"title": "Failed to invite the supplier",
"data": "response.data.message"
}
}
},
"enter_client": {
"$schema": "http://workflow.example.com/actions/form/schema.json",
"actor": "supplier",
"form": { "<ref>": "definitions.client_form" },
"display": "never",
"update": {
"select": "actors.client"
}
},
"invite_client": {
"$schema": "http://workflow.example.com/actions/invite/schema.json",
"actor": "supplier",
"invite": "client",
"responses": {
"ok": {
"display": "never"
},
"error": {
"display": "always",
"title": "Failed to invite the supplier",
"description": {
"<ref>": "response.data.message"
}
}
}
},
"upload": {
"$schema": "http://workflow.example.com/actions/upload/schema.json",
"actor": "supplier",
"accept": "application/pdf",
"responses": {
"ok": {
"title": "Provided a quotation",
"update": {
"select": "assets.quotation"
}
},
"error": {
"label": "An error occurred when uploading the quotation",
"display": "once"
}
}
},
"review": {
"$schema": "http://workflow.example.com/actions/review/schema.json",
"actor": "client",
"document": "assets.quotation",
"responses": {
"accept": {
"label": "Accept",
"title": "Accepted quotation"
},
"reject": {
"label": "Reject",
"title": "Rejected quotation"
}
},
"default_response": "accept"
}
},
"states": {
":initial": {
"actions": [
"request_quotation",
"enter_client"
],
"transitions": [
{
"action": "request_quotation",
"transition": "invite_supplier"
},
{
"action": "enter_client",
"transition": "provide_quote"
}
]
},
"invite_supplier": {
"action": "invite_supplier",
"transitions": [
{
"response": "ok",
"transition": "wait_for_quote"
},
{
"response": "error",
"transition": ":failed"
}
]
},
"invite_client": {
"action": "invite_client",
"transitions": [
{
"response": "ok",
"transition": "wait_for_review"
}
]
},
"wait_for_quote": {
"title": "Prepare quotation",
"instructions": {
"supplier": { "<tpl>": "{{ assets.request.description }} ({{ assets.request.urgency }} urgency)" }
},
"action": "upload",
"transitions": [
{
"response": "ok",
"transition": "wait_for_review"
}
]
},
"provide_quote": {
"title": "Provide quotation",
"action": "upload",
"transitions": [
{
"response": "ok",
"transition": "invite_client"
}
]
},
"wait_for_review": {
"title": "Review quotation",
"instructions": {
"client": "Please review and accept the quotation",
"supplier": "Please wait for the client to review the quotation."
},
"action": "review",
"transitions": [
{
"response": "accept",
"transition": ":success"
},
{
"response": "reject",
"transition": ":cancelled"
}
]
}
}
}
{
"$schema": "https://specs.letsflow.io/v0.1.0/scenario/schema.json#",
"id": "JKdf3jddfklsr834s312",
"title": "Product quotation",
"description": "Send a quotation requested by the client",
"actors": {
"supplier": {
"$ref": "https://specs.letsflow.io/v0.1.0/actor/schema.json#organization"
},
"client": {
"$ref": "https://specs.letsflow.io/v0.1.0/actor/schema.json#individual"
}
},
"assets": {
"request": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"urgency": {
"type": "string",
"enum": ["normal", "high", "critical"]
}
}
},
"quotation": {
"$ref": "https://specs.letsflow.io/v0.1.0/document/schema.json#"
}
},
"definitions": {
"request_form": {
"title": "Quotation request form",
"definition": [{
"fields": [{
"$schema": "http://specs.legalthings.one/draft-01/form/schema.json#external-select",
"label": "Supplier",
"name": "supplier",
"url": "https://jsonplaceholder.typicode.com/users",
"optionText": "name",
"optionValue": "{ name, email, phone }",
"required": true
},
{
"$schema": "http://specs.legalthings.one/draft-01/form/schema.json#textarea",
"label": "Description",
"name": "description",
"helptip": "Which service would you like a quotation for?"
},
{
"$schema": "http://specs.legalthings.one/draft-01/form/schema.json#select",
"label": "Urgency",
"name": "urgency",
"options": [{
"value": "normal",
"label": "Normal"
},
{
"value": "high",
"label": "High"
},
{
"value": "critical",
"label": "Critical"
}
]
}
]
}]
},
"client_form": {
"title": "Enter client information",
"definition": [{
"fields": [{
"$schema": "http://specs.legalthings.one/draft-01/form/schema.json#text",
"label": "Name",
"name": "name",
"required": true
},
{
"$schema": "http://specs.legalthings.one/draft-01/form/schema.json#email",
"label": "E-mail",
"name": "email",
"required": true
}
]
}]
}
},
"actions": {
"request_quotation": {
"$schema": "http://specs.legalthings.one/draft-01/action/schema.json#form-action",
"actor": "client",
"form": {
"<ref>": "definitions.request_form"
},
"responses": {
"ok": {
"title": "Quote quested by client"
}
}
},
"invite_supplier": {
"$schema": "http://specs.legalthings.one/draft-01/action/schema.json#invite-action",
"actor": "client",
"invite": "supplier",
"responses": {
"ok": {
"display": "never"
},
"error": {
"display": "always",
"title": "Failed to invite the supplier",
"description": {
"<ref>": "response.data.message"
}
}
}
},
"enter_client": {
"$schema": "http://specs.legalthings.one/draft-01/scenario/schema.json#form-action",
"actor": "supplier",
"form": {
"<ref>": "definitions.request_form"
},
"responses": {
"ok": {
"display": "never",
"update": {
"select": "actors.client"
}
}
}
},
"invite_client": {
"$schema": "http://specs.legalthings.one/draft-01/scenario/schema.json#invite-action",
"actor": "supplier",
"invite": "client",
"responses": {
"ok": {
"display": "never"
},
"error": {
"display": "always",
"title": "Failed to invite the supplier",
"description": {
"<ref>": "response.data.message"
}
}
}
},
"upload": {
"$schema": "http://specs.legalthings.one/draft-01/scenario/schema.json#upload-action",
"actor": "supplier",
"label": "Upload",
"accept": "application/pdf",
"responses": {
"ok": {
"title": "Uploaded quotation",
"update": {
"select": "assets.quotation",
"data": {
"$schema": "https://specs.letsflow.io/v0.1.0/document/schema.json#",
"name": {
"<tpl>": "Quotation {{ actors.client.name }} {{ response.date }}"
},
"date": {
"<ref>": "response.date"
},
"content_media_type": {
"<ref>": "response.data.media_type"
},
"content_encoding": {
"<ref>": "response.data.encoding"
},
"content": {
"<ref>": "response.data.content"
}
}
}
},
"error": {
"label": "An error occurred when uploading the quotation",
"display": "once"
}
}
},
"review": {
"$schema": "http://specs.legalthings.one/draft-01/action/schema.json#review",
"actor": "client",
"document": {
"<ref>": "assets.quotation"
},
"responses": {
"accept": {
"label": "Accept",
"title": "Accepted quotation"
},
"reject": {
"label": "Reject",
"title": "Rejected quotation"
}
},
"default_response": "approve"
},
"cancel": {
"$schema": "http://specs.legalthings.one/draft-01/action/schema.json#choose",
"actor": ["client", "supplier"],
"responses": {
"ok": {
"label": "Cancel",
"title": "Quotation withdrawn",
"transition": ":failed"
}
}
}
},
"states": {
":initial": {
"actions": ["request_quotation", "enter_client"],
"transitions": [{
"action": "request_quotation",
"transition": "invite_supplier"
},
{
"action": "enter_client",
"transition": "provide_quote"
}
]
},
"invite_supplier": {
"title": "Waiting on the supplier to participate in this process",
"actions": ["invite_supplier", "cancel"],
"default_action": "invite_supplier",
"transitions": [{
"action": "invite_supplier",
"response": "ok",
"transition": "wait_for_quote"
}]
},
"provide_quote": {
"title": "Prepare quotation",
"actions": ["upload", "cancel"],
"default_action": "upload",
"transitions": [{
"action": "upload",
"response": "ok",
"transition": "invite_client"
}]
},
"invite_client": {
"title": "Waiting on the client to participate in this process",
"actions": ["invite_client", "cancel"],
"default_action": "invite_client",
"transitions": [{
"action": "invite_client",
"response": "ok",
"transition": "wait_for_review"
}]
},
"wait_for_quote": {
"title": "Prepare quotation",
"instructions": {
"supplier": {
"<tpl>": "{{ assets.request.description }} ({{ assets.request.urgency }} urgency)"
}
},
"actions": ["upload", "cancel"],
"default_action": "upload",
"transitions": [{
"action": "upload",
"response": "ok",
"transition": "wait_for_review"
}],
"timeout": {
"<switch>": {
"on": {
"<ref>": "assets.request.urgency"
},
"options": {
"normal": "3b",
"high": "1b",
"critical": "6h"
}
}
}
},
"wait_for_review": {
"title": "Review quotation",
"instructions": {
"client": "Please review and accept the quotation",
"supplier": "Please wait for the client to review the quotation."
},
"actions": ["review", "cancel"],
"default_action": "review",
"timeout": "7d",
"transitions": [{
"action": "review",
"response": "accept",
"transition": ":success"
},
{
"action": "review",
"response": "deny",
"transition": ":failed"
}
]
}
}
}
https://specs.letsflow.io/v0.3.0/scenario#
A unique identifier. If the scenario is part of a Live Contract, this must be resource id that's valid for the event chain.
The id MUST point to an immutable version of the scenario. Modifying the scenario SHOULD always result in a new id. Previous versions of the scenario SHOULD remain available.
The title of the scenario.
A description of the procedure shown as scenario details.
Object with JSON Schema, defining the properties for each actor. The keys of the object is used to reference the actor. The actor schema must define an object.
Object with JSON schema, defining the properties for each asset. The keys of the object is used to reference the asset. The asset schema must define an object.
An object with constant values and predefined objects. This can be used to define things needed in multiple actions and/or states.
Even if it's only used in a single action or state, using definitions helps to keep actions and states small and readable.
Set of the actions of the scenario. The keys of the object are used as reference of the action.
Set of all states of the scenario. The keys of the object are used as reference of the state.
Last modified 3yr ago