Loan Application - Temporal.io based Worker
This tutorial in a nutshell
In this tutorial, we will build a simple Temporal-based Worker in Typescript language that will manage a Loan Application business process in KuFlow. Our example will model a Workflow whose purpose is to fill up an application form for approval. We will include some special rules, such as automatic approval for amounts below a certain quantity, and the use of different currencies which require REST calls to a third-party application.
Prerequisites
Before starting our Worker for the first time, we must register it in KuFlow (app.kuflow.com). After familiarizing yourself with the user interface, you are ready to perform the necessary configurations for our Worker. To do so, click on the Settings
menu. If you do not see this menu, you probably do not have the necessary permissions to define processes, so you will have to request it from your Organization administrators, or simply create a FREE new account.
Create the credentials for the Worker
We will configure an APPLICATION
that will provide us with the necessary credentials so that our Worker (written in
TypeScript and located in your own machine) can interface with KuFlow.
Go to the Settings > Applications
menu and click on Add application
. We set the name we want and save. Next,
you will get the first data needed to configure our Worker.
- Identifier: Unique identifier of the application. For this tutorial: LoanApp
- Later in this tutorial, we will configure it in the
kuflow.api.client-id
property of our example.
- Later in this tutorial, we will configure it in the
- Token: Password for the application.
- Later in this tutorial, we will configure it in the
kuflow.api.client-secret
property of our example.
- Later in this tutorial, we will configure it in the
Finally, you get something like:
Create the process definition
We need to create the definition of the process that will execute our Workflow. In this section, we will configure the KuFlow tasks of which it is made up as well as the information necessary to complete said tasks, the process access rules (i.e. RBAC), as well as another series of information. To do this we go to the Setting > Processes
menu and create a new process.
A Process Definition with the following data:
- Description
- Free text description about the Workflow.
- Workflow
- Workflow Engine
- KuFlow Engine, because we are designing a Temporal-based Worker.
- Workflow Application
- LoanApp, the application to which our Worker will connect to
- Task queue
- The name of the Temporal queue where the KuFlow tasks will be set. You can choose any name, later you will set this same name in the appropriate configuration in your Worker. For this tutorial: SampleQueue.
- Type
- It must match the name of the TypeScript function of the Workflow. For this tutorial, SampleLoanWorkflow is the name you should type in this input.
- Workflow Engine
- Metadata
- Reason metadata: To require the user to indicate a personalized metadata (reason) when starting the process.
- Code: REASON
- Name: Reason
- Field Type: Text
- Mandatory: Yes
- Editable: Yes (To allow editing until the process has been completed)
- Reason metadata: To require the user to indicate a personalized metadata (reason) when starting the process.
- Code: FIRST_NAME
- Name: First name
- Field Type: Text
- Mandatory: No
- Editable: No
- Reason metadata: To require the user to indicate a personalized metadata (reason) when starting the process.
- Code: LAST_NAME
- Name: Last name
- Field Type: Text
- Mandatory: No
- Editable: No
- Reason metadata: To require the user to indicate a personalized metadata (reason) when starting the process.
We must also define the Permissions
- At least, one user or group of users must have the role of
INITIATOR
in order to instantiate the process through the application. In this tutorial, we will allow all users from this organization to be able to process initiation (Groups > Users) - At least, one user or group of users will assume the task of loans approvals. In this tutorial, we have defined the user Murph, so we will also give her the role of
PROCESS MANAGER
.
We define two Tasks Definitions in the process with the following data:
-
Task "Loan Application Form"
- Description: Free text description about the Task.
- Code: LOAN_APPLICATION
- Permissions:
- Groups > Users as Candidate (in this tutorial, we will allow all users from this organization to fill up a loan application form)
- Elements:
- First Name
- Name: First Name
- Code: FIRST_NAME
- Type: Field
- Properties: Mandatory, remaining checked.
- Field Type: Text
- Last Name
- Name: Last Name
- Code: LAST_NAME
- Type: Field
- Properties: Mandatory, remaining checked.
- Field Type: Text
- Amount
- Name: Amount
- Code: AMOUNT
- Type: Field
- Properties: Mandatory, remaining checked.
- Field Type: Numeric
- Currency
- Name: Currency
- Code: CURRENCY
- Type: Field
- Properties: Mandatory, remaining checked.
- Field Type: Decision
- Code: "EUR" / Name: "Euro"
- Code: "USD" / Name: "United States dollar"
- Code: "GBP" / Name: "Pound sterling"
- First Name
-
Task "Approve Loan"
- Description: Free text description about the Task.
- Code: APPROVE_LOAN
- Permissions:
- Murph as Candidate
- Elements:
- First Name
- Name: First Name
- Code: FIRST_NAME
- Type: Field
- Properties: Read-only, remaining checked.
- Field Type: Text
- Last Name
- Name: Last Name
- Code: LAST_NAME
- Type: Field
- Properties: Read-only, remaining checked.
- Field Type: Text
- Amount
- Name: Amount
- Code: AMOUNT
- Type: Field
- Properties: Read-only, remaining checked.
- Field Type: Numeric
- Approval
- Name: Approval
- Code: APPROVAL
- Type: Field
- Properties: Mandatory, remaining checked.
- Field Type: Decision
- Code: "YES" / Name: "Approved"
- Code: "NO" / Name: "Rejected"
- First Name
We must also define the Permissions
- At least, one user or group of users must have the role of
INITIATOR
in order to instantiate the process through the application. In this tutorial, we will allow all users from this organization to be able to process initiation (Default Group) - At least, one user or group of users will assume the task of loans approvals. In this tutorial, we have defined the user Murph,
so we will also give her the role of
PROCESS MANAGER
.
Source code for our Worker
The source code for this example can be obtained from our typescript/js examples repository.
However, an alternative methodology could be to download the example template code for the process we are going to implement and compare it with the complete example in our repository. To download the initial template you must access the workflow definition in the App, and once configured, use the download template option.
Main technologies used in the example
This code will serve as a starting point for implementing our Loan Application worker. The requirements for its use are the following:
- TypeScript JDK
- You need to have NodeJS installed on your system. The current example code uses version 16+.
- IDE
- An IDE with good TypeScript support is necessary to work comfortably. You can use VSCode, IntelliJ Idea, Eclipse or any other with corresponding TypeScript plugins.
To make things simpler, the following dependencies have been used in our example:
- KuFlow JS SDK
- Provide some activities and utilities to work with KuFlow.
- Temporal TypeScript SDK
- To perform GRPC communications with the KuFlow temporal service.
Implementation details
The workflow
In this section, we will make the fundamental steps to creating a workflow for this business process:
- Users in an organization can create a Loan Application.
- If the loan is over 5,000 euros, manager approval is required.
- The user can indicate the amount requested in several currencies.
- A third party API will proceed to convert the currency to Euros at the current time.
- The manager is the only authorized user to approve loans.
- The user is informed of the final decision on the loan.
We modify the method that creates the Loan Form Application task so that it returns the task to the workflow upon completion.
workflow.ts
async function createTaskLoanApplicationForm(workflowRequest: WorkflowRequest): Promise<Task> {
const taskId = uuid4()
const taskRequest: Task = {
objectType: 'TASK',
id: taskId,
processId: workflowRequest.processId,
taskDefinition: {
code: 'LOAN_APPLICATION',
},
}
await createTaskAndWaitCompleted(taskRequest)
const { task } = await kuFlowActivities.KuFlow_Engine_retrieveTask({ taskId })
return task
}
async function createTaskAndWaitCompleted(task: Task): Promise<void> {
const taskId = task.id
if (taskId == null) {
throw Error('task id is required')
}
await kuFlowActivities.KuFlow_Engine_createTask({ task })
await condition(() => kuFlowCompletedTaskIds.includes(taskId))
}
We modify the function that manages the Loan Approval task, so that in its creation the First Name, Last Name fields are completed with the data of the initial task of the form. In the same way, the value for the Amount requested is added, once transformed to Euros from the source currency.
workflow.ts
async function createTaskApproveLoan(taskLoanApplication: Task, amountEUR: number): Promise<Task> {
const taskId = uuid4()
const firstName = TaskUtils.getElementValueAsString(taskLoanApplication, 'FIRST_NAME')
const lastName = TaskUtils.getElementValueAsString(taskLoanApplication, 'LAST_NAME')
const taskRequest: Task = {
objectType: 'TASK',
id: taskId,
processId: taskLoanApplication.processId,
taskDefinition: {
code: 'APPROVE_LOAN',
},
}
TaskUtils.addElementValueAsString(taskRequest, 'FIRST_NAME', firstName)
TaskUtils.addElementValueAsString(taskRequest, 'LAST_NAME', lastName)
TaskUtils.addElementValueAsString(taskRequest, 'AMOUNT', amountEUR.toString())
await createTaskAndWaitCompleted(taskRequest)
const { task } = await kuFlowActivities.KuFlow_Engine_retrieveTask({ taskId })
return task
}
The notification tasks (approval or rejection) will be left as they are in the downloaded template.
We need to modify the main method of the workflow with the following content:
workflow.ts
export async function SampleEngineWorkerLoanWorkflow(workflowRequest: WorkflowRequest): Promise<WorkflowResponse> {
const kuFlowCompletedTaskIds: string[] = []
setHandler(kuFlowEngineCompletedTaskSignal, (taskId: string) => {
kuFlowCompletedTaskIds.push(taskId)
})
logger.info('Start', {})
const taskLoanApplication = await createTaskLoanApplicationForm(workflowRequest)
await updateProcessMetadata(taskLoanApplication)
const currency = TaskUtils.getElementValueAsString(taskLoanApplication, 'CURRENCY')
const amount = TaskUtils.getElementValueAsString(taskLoanApplication, 'AMOUNT')
const amountEUR = await convertToEuros(currency, amount)
let loanAuthorized = true
if (amountEUR > 5_000) {
const taskApproveLoan = await createTaskApproveLoan(taskLoanApplication, amountEUR)
const approval = TaskUtils.getElementValueAsString(taskApproveLoan, 'APPROVAL')
loanAuthorized = approval === 'YES'
}
const process = await retrieveProcess(workflowRequest)
if (loanAuthorized) {
await createTaskNotificationGranted(process)
} else {
await createTaskNotificationRejection(process)
}
logger.info('End', {})
return { message: 'OK' }
}
The activities
Our workflow interacts with two external systems, the first one is the KuFlow REST API. For this we use a set of activities already provided in the SDK. On the other hand, we need to connect to a third party API that provides real-time currency conversion. For this we create the following activity.
activities.ts
async function currencyConvert(amount: string, from: string, to: string): Promise<string> {
const amountNumber = parseFloat(amount)
const fromTransformed = transformCurrencyCode(from)
const toTransformed = transformCurrencyCode(to)
const endpoint = `https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/${fromTransformed}/${toTransformed}.json`
const response = await axios.get(endpoint)
const conversion = response.data[toTransformed]
return (amountNumber * conversion).toString()
}
The worker
We need to indicate that our Temporal worker, in addition to implementing the KuFlow activities, implements the activity that connects to a third-party API and obtains a currency transformation.
worker.ts
const workerProperties = loadConfiguration()
// Instantiate KuFlow rest client
const kuFlowRestClient = new KuFlowRestClient(
{
clientId: workerProperties.kuflow.api.clientId,
clientSecret: workerProperties.kuflow.api.clientSecret,
},
{
endpoint: workerProperties.kuflow.api.endpoint,
},
)
// Configure kuflow temporal connection
const kuflowTemporalConnection = await KuflowTemporalConnection.instance({
kuflow: {
restClient: kuFlowRestClient,
},
temporalio: {
connection: {
address: workerProperties.temporal.target,
},
worker: {
taskQueue: workerProperties.temporal.kuflowQueue,
workflowsPath: require.resolve('./workflows'),
activities: {
...createKuFlowActivities(kuFlowRestClient),
...Activities,
},
},
},
})
Runtime.instance().logger.info('Worker connection successfully established')
await kuflowTemporalConnection.runWorker()
await kuflowTemporalConnection.close()
Worker configuration
The last step of this section is filling up the application configuration information. You must complete all the settings and replace the example values. The appropriate values can be obtained from the KuFlow application. Check out the Create the credentials for the Worker section of this tutorial.
# ===================================================================
# PLEASE COMPLETE ALL CONFIGURATIONS BEFORE STARTING THE WORKER
# ===================================================================
kuflow:
api:
# ID of the APPLICATION configured in KUFLOW.
# Get it in "Application details" in the Kuflow APP.
client-id: FILL_ME
# TOKEN of the APPLICATION configured in KUFLOW.
# Get it in "Application details" in the Kuflow APP.
client-secret: FILL_ME
temporal:
# Temporal Queue. Configure it in the "Process definition" in the KUFLOW APP.
kuflow-queue: "SampleQueue"
Please note that this is a YAML
, respect the indentation.
We can test this scenario, initiating the process several times, in order to create different applications and approvals
Summary
In this tutorial, we have covered the basics of creating a workflow in KuFlow for loan applications. We have defined a new process definition and we have built a workflow that contemplates the required business rules defined above.
We sincerely hope that this step-by-step guide will help you to understand better how KuFlow can help your business to have better and more solid business processes.