BPMN DSL

This DSL will bring your domain into your BPMN-Process.

As the pattern is always the same, we can setup each BPMN Element in the same way.

object BpmnElement extends CompanyBpmn<Element>Dsl:

  val processName = "mycompany-myproject-myelement" // depending on the element this can be different
  lazy val descr = "my element..."

  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec

  case class Out(...)
  object Out:
    given ApiSchema[Out] = deriveApiSchema
    given InOutCodec[Out] = deriveInOutCodec

  lazy val example = <bpmnElement>(
    In(),
    Out(),
  )
end BpmnElement

So each BPMN Element has:

Special Case Enums

If you have an Enum as an In or Out class, you need to define the example like this:


lazy val example = <bpmnElement>(
  In.CaseA(),
  Out.CaseA(),
  ).withEnumInExamples(In.CaseB())
  .withEnumOutExamples(Out.CaseB())

We support the following elements:

Process

The Process is the main element of a BPMN. It is the most complex element and looks like this:

object MyProcess extends CompanyBpmnProcessDsl:

  val processName = "mycompany-myproject-myprocess"
  lazy val descr = "my process..."
  
  case class In(
    ...
    inConfig: Option[InConfig] = None
  ) extends WithConfig[InConfig]
  
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  case class InConfig(
    // Process Configuration
    ...
    // Mocks
    ... )
  object InConfig:
    given ApiSchema[InConfig] = deriveApiSchema
    given InOutCodec[InConfig] = deriveInOutCodec
    
  case class InitIn(...)
  object InitIn:
    given ApiSchema[InitIn] = deriveApiSchema
    given InOutCodec[InitIn] = deriveInOutCodec
  
  case class Out(...)
  object Out:
    given ApiSchema[Out] = deriveApiSchema
    given InOutCodec[Out] = deriveInOutCodec
  
  lazy val example = process(
    In(),
    Out(),
    InitIn()
  )
end MyProcess

Next to the In and Out classes we have an InitIn- and InConfig class.

InitIn

Each process has an InitWorker that is the first worker that is called when the process is started.

Use this class to:

InConfig

These are technical Process Variables, like:

The InitWorker will automatically put these variables on the process. That means you can override them for example in Postman

  • just set them as process variables (inConfig object is not needed).

Business Rule Tasks (Decision DMNs)

We support only Decision DMNs. The input is always a domain object (each field must be a simple value that matches a column of the dmn). As simple values we support:

A domain object is a case class as described in the Specification, with the exception, that each field must be a simple value that matches a column of the dmn.

Inputs are always domain objects.

In the DSL we have an element for each of the four different return types - so you don't mix up the types 😊.

singleEntry

This is a single result with one simple value.

singleEntry(
    in = Input("A"),
    out = 1
  )

singleResult

This is a single result with more than one value (domain object).

singleResult(
    in = Input("A"),
    out = ManyOutResult(1, "🤩")
)

collectEntries

This is a list of simple values.

collectEntries(
    in = Input("A"),
    out = Seq(1, 2)
  )

resultList

This is a list of domain objects.

resultList(
    in = Input("A"),
    out = List(ManyOutResult(1, "🤩"), ManyOutResult(2, "😂"))
  )

User Task

A User Task describes its form values that it offers and the values it must be completed with.

object MyUserTask extends CompanyBpmnUserTaskDsl:

  val name = "mycompany-myproject-myusertask"
  val descr: String = "my user task..."
  
  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  case class Out(...)
  object Out:
    given ApiSchema[Out] = deriveApiSchema
    given InOutCodec[Out] = deriveInOutCodec
  
  lazy val example = userTask(
    In(),
    Out()
  )
end MyUserTask

External Task

An External Task describes a worker. We distinguish different types of Tasks, which are described in the next subchapters.

Custom Task

A Custom Task is a description for a worker that does some business logic, like mapping.

In General, you can do whatever you want with a Custom Task. See also CustomWorker.

object MyCustomTask extends CompanyBpmnCustomTaskDsl:

  val topicName = "mycompany-myproject-myprocessV1.MyCustomTask"
  val descr: String = "my custom task..."
  
  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  case class Out(...)
  object Out:
    given ApiSchema[Out] = deriveApiSchema
    given InOutCodec[Out] = deriveInOutCodec
  
  lazy val example = customTask(
    In(),
    Out()
  )
end MyCustomTask

Init Task

An Init Task is a description for a worker that initializes a Process.

In General, you map the In object to the InitIn object like init process variables. See also InitWorker.

So no extra BPMN Element is needed for this, it is automatically defined by the Process.

object MyProcess extends CompanyBpmnProcessDsl:
  ...
  case class In(
    ...
    inConfig: Option[InConfig] = None
  ) extends WithConfig[InConfig]
  ...  
  case class InitIn(...)
  ...
end MyProcess

Service Task

A Service Task is a description for a worker that provides a REST API request.

See also ServiceWorker.

object MyServiceTask extends CompanyBpmnServiceTaskDsl:

  val topicName = "mycompany-myproject-myservicetask"
  val descr: String = "my service task..."
  val path = "POST: /myService"

  type ServiceIn = MyServiceBody
  type ServiceOut = NoOutput
  lazy val serviceInExample = MyServiceBody()
  lazy val serviceMock = MockedServiceResponse.success204

  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  case class Out(...)
  object Out:
    given ApiSchema[Out] = deriveApiSchema
    given InOutCodec[Out] = deriveInOutCodec
  
  lazy val example = serviceTask(
    In(),
    Out(),
    serviceMock,
    serviceInExample
  )
end MyServiceTask

This task is more specific, and so we need to define

At the moment we only support these 3 types of External Tasks. Depending on the use case we can add more types.

Receive Message Event

A Receive Message Event represents a catching message event. The input defines the message you expect. This works only as intermediate event. As we don't support throwing Message events we can simplify this to messageEvent:

object MyMessageEvent extends CompanyBpmnMessageEventDsl:

  val messageName = "mycompany-myproject-mymessage"
  val descr: String = "my message..."
  
  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  lazy val example = messageEvent(In())
end MyMessageEvent

Receive Signal Event

A Receive Signal Event represents a catching signal event. The input defines the signal you expect. This works only as intermediate event. As we don't support Throwing Signal events we can simplify this to signalEvent:

object MySignalEvent extends CompanyBpmnSignalEventDsl:

  val messageName = "mycompany-myproject-mysignal-{processInstanceId}"
  val descr: String = "my signal..."

  case class In(...)
  object In:
    given ApiSchema[In] = deriveApiSchema
    given InOutCodec[In] = deriveInOutCodec
  
  lazy val example = signalEvent(In())
end MySignalEvent

Timer Event

A Timer Event represents a timer event. There is no input needed, you can use it to describe the timers in your API doc, or using them in the Simulations to execute the job of the timer immediately. This works only as intermediate event.

object MyTimerEvent extends CompanyBpmnTimerEventDsl:

  val title = "mycompany-myproject-mytimer"
  val descr: String = "my timer..."
  
  lazy val example = timerEvent()
end MyTimerEvent