{"id":13408659,"url":"https://github.com/StephenOTT/Quintessential-Tasklist-Zeebe","last_synced_at":"2025-03-14T13:31:50.759Z","repository":{"id":148176293,"uuid":"202908772","full_name":"StephenOTT/Quintessential-Tasklist-Zeebe","owner":"StephenOTT","description":"The quintessential Zeebe tasklist for BPMN Human tasks with Drag and Drop Form builder, client and server side validations, and drop in Form Rendering","archived":false,"fork":false,"pushed_at":"2020-02-11T23:53:08.000Z","size":994,"stargazers_count":37,"open_issues_count":21,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-29T21:10:06.632Z","etag":null,"topics":["bpmn-human-tasks","vertx","zeebe","zeebe-client","zeebe-worker"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/StephenOTT.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-17T16:56:49.000Z","updated_at":"2024-05-27T14:30:25.000Z","dependencies_parsed_at":"2023-05-19T09:00:18.975Z","dependency_job_id":null,"html_url":"https://github.com/StephenOTT/Quintessential-Tasklist-Zeebe","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StephenOTT%2FQuintessential-Tasklist-Zeebe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StephenOTT%2FQuintessential-Tasklist-Zeebe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StephenOTT%2FQuintessential-Tasklist-Zeebe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StephenOTT%2FQuintessential-Tasklist-Zeebe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/StephenOTT","download_url":"https://codeload.github.com/StephenOTT/Quintessential-Tasklist-Zeebe/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243584387,"owners_count":20314749,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bpmn-human-tasks","vertx","zeebe","zeebe-client","zeebe-worker"],"created_at":"2024-07-30T20:00:54.419Z","updated_at":"2025-03-14T13:31:50.749Z","avatar_url":"https://github.com/StephenOTT.png","language":"Java","funding_links":[],"categories":["Applications"],"sub_categories":[],"readme":"# quintessential-tasklist-zeebe\nThe quintessential Zeebe tasklist for BPMN Human tasks with Drag and Drop Form builder, client and server side validations, and drop in Form Rendering\n\nWIP\n\nSetup SLF4J logging: `-Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory`\n\nvertx run command: `run com.github.stephenott.MainVerticle -conf src/main/java/com/github/stephenott/conf/conf.json`\n\nCurrent Zeebe Version: `0.21.0-alpha1`\nCurrent Vertx Version: `3.8.0`\nJava: `1.8`\n\n\n# Cluster Architecture\n\n![cluster-arch](./docs/design/cluster.png)\n\n- Clients, Workers, and Executors can be added at startup and during runtime.\n- Failed nodes in the Vertx Cluster (Clients, Workers, and Executors) will be re-instantiated through the vertx cluster manager's configuration. \n\n\n# Form Building UI\n\nThe Form Builder UI uses Formio.js as the Builder and Render.  \nThe schema that was generated from the builder is persisted and used during the User Task Submission with Form flow.\n\n![builder1](./docs/design/form/FormBuilder1-build.png)\n\n![builder2](./docs/design/form/FormBuilder2-build.png)\n\n![builder3](./docs/design/form/FormBuilder3-build.png)\n\n\nAnd then you can render and make a submission:\n\n![builder4](./docs/design/form/FormBuilder4-render.png)\n\n\nTry out the builder on: https://formio.github.io/formio.js/app/builder\n\n\n## User Task Submission with Form Data flow\n\n![dataflow](./docs/design/form/User-Task-Form-Completion-Flow.png)\n\n\n# ZeebeClient/Worker/Executor Data Flow\n\n![data flow](./docs/design/dataflow.png)\n\n\n# Configuration\n\nExtensive configuration capabilities are provided to control the exact setup of your application: \n\nThe Yaml location can be configured through the applications config.json.  Default is `./zeebe.yml`. \n\nExample:\n\n```yaml\nzeebe:\n  clients:\n    - name: MyCustomClient\n      brokerContactPoint: \"localhost:25600\"\n      requestTimeout: PT20S\n      workers:\n        - name: SimpleScriptWorker\n          jobTypes:\n            - type1\n          timeout: PT10S\n        - name: UT-Worker\n          jobTypes:\n            - ut.generic\n          timeout: P1D\n\nexecutors:\n  - name: Script-Executor\n    address: \"type1\"\n    execute: ./scripts/script1.js\n  - name: CommonGenericExecutor\n    address: commonExecutor\n    execute: classpath:com.custom.executors.Executor1\n  - name: IpBlocker\n    address: block-ip\n    execute: ./cyber/BlockIP.py\n\nuserTaskExecutors:\n  - name: GenericUserTask\n    address: ut.generic\n\nmanagementServer:\n  enabled: true\n  apiRoot: server1\n  corsRegex: \".*.\"\n  port: 8080\n  instances: 1\n  zeebeClient:\n    name: DeploymentClient\n    brokerContactPoint: \"localhost:25600\"\n    requestTimeout: PT10S\n\nformValidatorServer:\n  enabled: true\n  corsRegex: \".*.\"\n  port: 8082\n  instances: 1\n  formValidatorService:\n    host: localhost\n    port: 8083\n    validateUri: /validate\n    requestTimeout: 5000\n\nuserTaskServer:\n  enabled: true\n  corsRegex: \".*.\"\n  port: 8080\n  instances: 1\n```\n\n# Zeebe Clients\n\nA Zeebe Client is a gRPC channel to a specific Zeebe Cluster.\n\nA client maintains a set of \"Job Workers\", which are long polling the Zeebe Cluster for Zeebe Jobs that have a `type` listed in the `jobTypes` array.\n\nZeebe Clients have the following configuration:\n\n```yaml\nzeebe:\n  clients:\n    - name: MyCustomClient\n      brokerContactPoint: \"localhost:25600\"\n      requestTimeout: PT20S\n      workers:\n        - name: SimpleScriptWorker\n          jobTypes:\n            - type1\n          timeout: PT10S\n        - name: UT-Worker\n          jobTypes:\n            - ut.generic\n          timeout: P1D\n``` \n\nWhere `name` is the name of the client.  The same name could be used by multiple clients in the same server or by other servers.  The `name` is used as the `zeebeSource` in Executors and User Task Executors as the source system to send completed/failed Zeebe Jobs back to.\n\nWhere `workers` is a array of Zeebe Worker definitions.  A worker definition has a `name` and a list of `jobTypes`.\n\n`name` is the worker name that is provided to Zeebe as the worker that requested the job.\n\n`jobTypes` is the lsit of Zeebe job `types` that will be queried for using long polling.\n\nJobs that are retrieved will be routed to the event bus using the address: `job.:jobType:`, where `:jobType:` is the specific Zeebe job's `type` property.\nMake sure you have executors (Polyglot, User Task or custom) on the network connected to the vertx cluster or else the job will not be consumed by a worker.\n \n Take note of the usage of the `timeout` which is the deadline that the job will be locked for. \n The usage has special applicability for Jobs that you want to use with User Task; where you will want to set the timeout as a much longer period than a typical executor. \n\n\n# Executors\n\nExecutors provide a polyglot execution solution for completing Zeebe Jobs.\n\nExecutors have the following configuration:\nExample of three different executors:\n\n```yaml\nexecutors:\n  - name: Script-Executor\n    address: \"type1\"\n    execute: ./scripts/script1.js\n    instances: 2\n  - name: CommonGenericExecutor\n    address: commonExecutor\n    execute: classpath:com.custom.executors.Executor1\n  - name: IpBlocker\n    address: block-ip\n    execute: ./cyber/BlockIP.py\n```\n\nExecutors can execute scripts and classes as defined in the executor's polyglot capabilities.\n\nWhere `address` is the Zeebe job `type` that would be configured in the task in the BPMN.\n\nWhere `execute` is the class/script that will be executor when jobs are sent to this executor\n\nWhere `name` is the unique name of the Executor used for logging purposes.\n\nYou can deploy a Executor with multiple `instances` to provide more more parallel throughput capacity.\n\nRequired properties: `name`, `address`, `execute`\n\nCompletion of Jobs sent to Executors is captured over the event bus with the JobResult object.  \nCompleted (successfully or a failure such as a business error) are sent as a JobResult to event bus address: `sourceClient.job-aciton.completion`.\n\nWhere `sourceClient` is the ZeebeClient `name` that is used in the `zeebe.clients[].name` property.\n\nThe `sourceClient` ensures that a completed job can be sent back to the same Zeebe Cluster, but not necessarily using the same instance of a ZeebeClient that consumed the job.\n\nJobResult's that have a `result=FAIL` will have their corresponding Zeebe Job actioned as a Failed Job.\n\n\n# User Task Executors\n\nUser Task(UT) Executors are a special type of executor that are dedicated to the logic handling of BPMN User Tasks.\n\nUT Executors have the following configuration:\n\n```yaml\nuserTaskExecutors:\n  - name: GenericUserTask\n    address: ut.generic\n    instances: 1\n```\n\nRequired properties: `name`, `address`\n\nWhere `address` is the Zeebe job `type` that would be configured in the task in the BPMN.\n\nInternally executors have their addresses prefixed with a common job prefix to ensure proper message namespacing.\n\nWhere `name` is the unique name of the UT Executor used for logging purposes.\n\nYou can deploy a UT Executor with multiple `instances` to provide more more parallel throughput capacity.\n\nUT Executors primary function is to provide capture of UTs from Zeebe and convert the Zeebe jobs into a UserTaskEntity.\nA UserTaskEntity is then saved in the storage of choice (such as a DB).\n\nCompletion of User Tasks is captured over the event bus with the JobResult object.\n\nCompleted (successfully or a failure such as a business error) are sent as a JobResult to event bus address: `sourceClient.job-aciton.completion`.\n\nWhere `sourceClient` is the ZeebeClient `name` that is used in the `zeebe.clients[].name` property.\n\nThe `sourceClient` ensures that a completed job can be sent back to the same Zeebe Cluster, but not necessarily using the same instance of a ZeebeClient that consumed the job.\n\nJobResult's that have a `result=FAIL` will have their corresponding Zeebe Job actioned as a Failed Job.\n\n\n## User Tasks\n\nThe default build of User Tasks seeks to provide a duplicate or similar User Task experience as Camunda's User Tasks implementation.\n\nSee UserTaskEntity.class, UserTaskConfiguration.class for more details.\n\nA User Task can be configured in the Zeebe BPMN using custom headers.  The supported headers are:\n\n|key|value|description|\n|------|------|----------|\n|title|`string`|The title of the task.  Can be any string value that will be interpreted by the User Task storage system.|\n|description|`string` |The description of the task.  Can be any string value that will be interpreted by the User Task storage system.|\n|priority|`int`|defaults to 0|\n|assignee|`string`|The default assignee of the task. A single value.|\n|candidateGroups|`string`|The list of groups that are candidates to claim this task. Comma separated list of strings.  Example: `\"cg1, cg2, cg3\"`|\n|candidateUsers|`string`|The list of users that are candidates to claim this task.  Comma separated list of strings.  Example: `\"cu1, cu2, cu3\"`|\n|dueDate|`string`|The date on which the User Task is due.  ISO8601 format|\n|formKey|`string`|A value that represents the specific form that should be used by the user when completing this task.|\n\n\nWhen generating a UserTaskEntity, some additional properties are stored for usage and indexing and convenience:\n\nIn addition to the custom header values above, the following is stored in the UserTaskEntity:\n\n|key|value|description|\n|------|------|----------|\n|taskId|`string`|The unique ID of the task.  Typically will be a business centric key defined during configuration.  If not ID is provided then defaults to `user-task--:UUID:` where `:UUID:` is a random UUID.|\n|zeebeSource|`string`|The source ZeebeClient `name` that the ZeebeJob was retrieved from.\n|zeebeDeadline|`instant`|The Zeebe Job deadline property|\n|zeebeJobKey|`long`|The unique job ID of the Zeebe Job.|\n|bpmnProcessId|`string`|The BPMN Process Definition ID|\n|zeebeVariables|`Map of String:Object`|The variables from the Zeebe Job|\n|metadata|`Map of String:Object`|A generic data holder for additional User Task metadata|\n\n# Form Validation Server\n\nThe Form Validation Server provides HTTP endpoints for validation a Form Submission based on a provided Form Schema.\n\nConfiguration:\n\n```yaml\nformValidatorServer:\n  enabled: true\n  corsRegex: \".*.\"\n  port: 8082\n  instances: 1\n  formValidatorService:\n    host: localhost\n    port: 8083\n    validateUri: /validate\n    requestTimeout: 5000\n```\n\nWhere `formValidatorService` is the Form Validator service that performs the actual form validation.\n\nExample Validation Request:\n\nPOST: `localhost:8083/validate`\n\nBody:\n\n```json\n{\n    \"schema\":{\n            \"display\": \"form\",\n            \"components\": [\n                {\n                    \"label\": \"Text Field\",\n                    \"allowMultipleMasks\": false,\n                    \"showWordCount\": false,\n                    \"showCharCount\": false,\n                    \"tableView\": true,\n                    \"alwaysEnabled\": false,\n                    \"type\": \"textfield\",\n                    \"input\": true,\n                    \"key\": \"textField2\",\n                    \"defaultValue\": \"\",\n                    \"validate\": {\n                        \"customMessage\": \"\",\n                        \"json\": \"\",\n                        \"required\": true\n                    },\n                    \"conditional\": {\n                        \"show\": \"\",\n                        \"when\": \"\",\n                        \"json\": \"\"\n                    },\n                    \"inputFormat\": \"plain\",\n                    \"encrypted\": false,\n                    \"properties\": {},\n                    \"customConditional\": \"\",\n                    \"logic\": [],\n                    \"attributes\": {},\n                    \"widget\": {\n                        \"type\": \"\"\n                    },\n                    \"reorder\": false\n                },\n                {\n                    \"type\": \"button\",\n                    \"label\": \"Submit\",\n                    \"key\": \"submit\",\n                    \"disableOnInvalid\": true,\n                    \"theme\": \"primary\",\n                    \"input\": true,\n                    \"tableView\": true\n                }\n            ],\n            \"settings\": {\n            }\n        },\n    \"submission\":{\n    \"data\": {\n        \"textField2\": 123,\n        \"dog\": \"cat\"\n    },\n    \"metadata\": {}\n}\n}\n```\n\nResponse if validation passes:\n\n```json\n{\n    \"processed_submission\": {\n        \"textField2\": \"sog\"\n    }\n}\n```\n\nNotice that the extra `dog` property is removed because it is not a valid field in the form schema.\n\nResponse if validation fails:\n\n```json\n{\n    \"isJoi\": true,\n    \"name\": \"ValidationError\",\n    \"details\": [\n        {\n            \"message\": \"\\\"textField2\\\" must be a string\",\n            \"path\": \"textField2\",\n            \"type\": \"string.base\",\n            \"context\": {\n                \"value\": 123,\n                \"key\": \"textField2\",\n                \"label\": \"textField2\"\n            }\n        }\n    ],\n    \"_object\": {\n        \"textField2\": 123,\n        \"dog\": \"cat\"\n    },\n    \"_validated\": {\n        \"textField2\": 123\n    }\n}\n```\n\nThe validation service is also available over the event bus at the `address` property defined in the Form Validation Server configuration.\n\n\n# Management Server\n\nThe management server provides HTTP endpoints for working with Zeebe clusters\n\nConfiguration:\n\n```yaml\nmanagementServer:\n  enabled: true\n  apiRoot: server1\n  corsRegex: \".*.\"\n  port: 8080\n  zeebeClient:\n    name: DeploymentClient\n    brokerContactPoint: \"localhost:25600\"\n    requestTimeout: PT10S\n  instances: 1\n  fileUploadPath: ./tmp/uploads\n```\n\nrequired fields: `apiRoot`, `zeebeClient`\n\n`apiRoot` must be unique.\n\n## Deploy Workflow\n\n`POST localhost:8080/server1/deploy`\n\nHeaders:\n- `Content-Type: multipart/form-data`\n\nform-data:\n- file name (must be a .bpmn or .yaml file) : file upload (the binary file you are uploading such as a .bpmn file)\n\nWhere `server1` is the `apiRoot` value defined in the YAML configuration.\n\nYou can deploy many management servers as needed.  Each server can be deployed for different zeebe clusters.\n\nYou can deploy the same server with multiple `instances` to provide more throughput. \n\n## Create Workflow Instance / Start Workflow\n\n`POST localhost:8080/server1/create-instance`\n\nHeaders:\n- `Content-Type: application/json`\n- `Accept: application/json`\n\nJson Body:\n\n```json\n{\n  \"workflowKey\": 1234567890\n}\n```\n\nWhere `workflowKey` is the unique workflow key that was generated for the BPMN process/pool during deployment.\n\nYou may also use:\n\n```json\n{\n  \"bpmnProcessId\": \"myProcess\",\n  \"bpmnProcessVersion\": 2\n}\n```\n\nWhere `bpmnProcessId` is the BPMN's process Id property (sometimes referred to as a process key).\nThe `bpmnProcessVersion` is optional.  You can set the version number or set as `-1` which means \"latest version\" / newest.  If you do not provide the property it will default to latest version.\n\n`varaibles` can also be provided as a json object:\n\n```json\n{\n  \"workflowKey\": 1234567890,\n  \"variables\": {\n    \"myVar1\": 123,\n    \"myVar2\": \"some value\",\n    \"myVarABC\": [1,2,5,10],\n    \"myVarXYZ\": {\n        \"1\": \"A\",\n        \"2\": \"B\"\n    }\n  }\n}\n```\n\nThe variables will be injected into the created workflow instance.\n\n\n# User Task Server\n\nA User Task HTTP server that provides User Task persistence, querying, completion, etc.\n\nThe server also provides a Form Schema Entity persistence, querying, and validation of submissions against the schema. \nThe Form Schema is what will be submitted to the Form Validator Service.\n\n## Server Configuration\n\n```yaml\nuserTaskServer:\n  enabled: true\n  corsRegex: \".*.\"\n  port: 8080\n  instances: 1\n```\n\n## Actions:\n\n1. Save Form Schema\n1. Complete User Task\n1. Get User Tasks\n1. Submit Form to Complete a User Task\n1. Delete User Task (TODO)\n1. Claim User Task (TODO)\n1. UnClaim User Task (TODO)\n1. Assign User Task (TODO)\n1. Create Custom User Task (not linked to Zeebe Job)\n\n## Save Form Schema\n\nPOST `/form/schema`\n\n```json\n{\n  \"owner\": \"Department-1\",\n  \"key\": \"MySimpleForm1\",\n  \"title\": \"My Simple Form 1\",\n  \"schema\": {\n    \"display\": \"form\",\n    \"components\": [\n      {\n        \"label\": \"Text Field\",\n        \"allowMultipleMasks\": false,\n        \"showWordCount\": false,\n        \"showCharCount\": false,\n        \"tableView\": true,\n        \"alwaysEnabled\": false,\n        \"type\": \"textfield\",\n        \"input\": true,\n        \"key\": \"textField2\",\n        \"defaultValue\": \"\",\n        \"validate\": {\n          \"customMessage\": \"\",\n          \"json\": \"\",\n          \"required\": true\n        },\n        \"conditional\": {\n          \"show\": \"\",\n          \"when\": \"\",\n          \"json\": \"\"\n        },\n        \"inputFormat\": \"plain\",\n        \"encrypted\": false,\n        \"properties\": {},\n        \"customConditional\": \"\",\n        \"logic\": [],\n        \"attributes\": {},\n        \"widget\": {\n          \"type\": \"\"\n        },\n        \"reorder\": false\n      },\n      {\n        \"type\": \"button\",\n        \"label\": \"Submit\",\n        \"key\": \"submit\",\n        \"disableOnInvalid\": true,\n        \"theme\": \"primary\",\n        \"input\": true,\n        \"tableView\": true\n      }\n    ],\n    \"settings\": {\n    }\n  }\n}\n```\n\nThe `key` property is the `formKey`  value you setup in your zeebe task custom headers.\n\nRequired fields: `owner`, `key`, `title`, `schema`\n\n\n## Complete User Task\n\nMainly used as a administrative endpoint to complete a User Task without any Form\n\nPOST `/task/complete`\n\n```json\n{\n  \"job\": 2251799813685292,\n  \"source\": \"MyCustomClient\",\n  \"completionVariables\": {}\n}\n```\n\n`Source` is the zeebe client name configured in your configuration yaml.\n\n\n## Get Tasks\n\nGET `/task`\n\nJSON Body:\n\nQuery is run as a `AND` query on each of the arguments\n\n```json\n{\n  \"taskId\": \"\",\n  \"state\": \"\",\n  \"title\": \"\",\n  \"assignee\": \"\",\n  \"dueDate\": \"\",\n  \"zeebeJobKey\": \"\",\n  \"zeebeSource\": \"\",\n  \"bpmnProcessId\": \"\"\n}\n```\n\nYou can pass `{}` as the body if you want to return all User Tasks.\n\n\n## Submit Task with Form\n\nPOST `/task/id/:taskId/submit`\n\nExample: `localhost:8088/task/id/user-task--080946c6-1355-4cd7-9fcf-86fc9c46d4c4/submit`\n\nJson Body:\n\n```json\n{\n    \"data\": {\n        \"textField2\": \"sog\",\n        \"dog\": \"cat\"\n    },\n    \"metadata\": {}\n}\n```\n\nThis endpoint acts the same as the Validation Server's `/validate` endpoint.  The difference is the User Task's endpoint will complete the User Task entity in the DB if the form is valid, and the Form fields will be saved in the Zeebe workflow as variables when the Job is completed.\n\nUpon successful form validation, and assuming the User Task is not already completed, then the User Task will be made complete and the completion variables will be saved. \nThen a background worker is watching for completed user tasks and will attempt to report this back to the Zeebe Job.  \nThe behaviour is this way so you can complete User Tasks without having to have a active connection to the Zeebe Cluster.\n\n## Delete User Task\n\nTODO...\n\n\n## Claim User Task\n\nTODO...\n\n## UnClaim User Task\n\nTODO...\n\n## Assign User Task\n\nTODO...\n\n## Create Custom User Task (not backed by Zeebe Job)\n\nTODO...\n\n----\n\n# Raw Notes\n\n1. Implements clustering and scaling through Vertx instances.\n1. ZeebeClientVerticle can increase in number of instances: 1 instance == 1 ZeebeClient Channel connection.\n1. ExecutorVerticle is independent of ZeebeClient.  You can scale executors across the cluster to any number of instances and have full cluster feature set.\n1. a JobResult is what holds the context of if a Zeebe Failure should occur in the context of the actual Work that a executor preformed.\n1. Management HTTP takes a apiRoot namespace which is the prefix for the api calls to deploy and start process instances\n1. TODO: Add a send message HTTP verticle\n1. UserTaskConfiguration is the data that is received from a Zeebe Custom Headers which is used to generate the Entity\n1. UserTaskVerticle is a example of a custom worker.  I have made them individual so User Tasks can be managed as stand along systems\n1. The Client Name property of the Client config is used as the EB address namespace for sending job completions back over the wire\n1. TODO move executeBlocking code into their own worker verticles with their own thread pools\n1. sourceClient is passed over the wire as a header which represents the client Name.  The client name is the client (or any instance of that name/id) that is used to send back into zeebe.  This supports multiple clients to different brokers (representing tenants for data separation)\n1. Breakers needs to be added\n1. Polling for Jobs is a executeBlocking action.  When polling is complete (found jobs or did not find jobs), it will call the poll jobs again.  It assumes long polling is enabled.\n1. TODO review defaults and setup of entity build in the user task verticle as its very messy right now.\n1. Management Server uses the route namespacing because it is assumed that security will be added by a proxy in the network.  If app level security needs to be added, then the ManagementHttpVerticle can be easily copied and replaced with security logic.\n1. TODO move EB addresses in a global static class for easy global management\n1. TODO fix up the logging to be DEBUG and cleanup the language as the standard is all over the place at the moment.  Also inlcude more context info for when reading the log as its unclear.\n1. TODO ***** Add the defaults logic for the User Task assignments, where if the headers that are not provided in zeebe then the user tasks entity will default to those configured values.\n1. TODO add the overrides logic: where if a override is provided then only the logic from the override is used and the provided header does not matter\n1. TODO Refactor error handling on HTTP requests to provider better json errors\n\n```xml\n...\n\u003cbpmn:extensionElements\u003e\n    \u003czeebe:taskDefinition type=\"ut.generic\" retries=\"3\"/\u003e\n    \u003czeebe:taskHeaders\u003e\n        \u003czeebe:header key=\"title\" value=\"my user task1\" /\u003e\n        \u003czeebe:header key=\"assignee\" value=\"stephen\" /\u003e\n        \u003czeebe:header key=\"formKey\" value=\"myCustomForm\" /\u003e\n    \u003c/zeebe:taskHeaders\u003e\n\u003c/bpmn:extensionElements\u003e\n...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStephenOTT%2FQuintessential-Tasklist-Zeebe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FStephenOTT%2FQuintessential-Tasklist-Zeebe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStephenOTT%2FQuintessential-Tasklist-Zeebe/lists"}