Skip to content

Migrating from version 1

Stephan Pelikan edited this page Oct 11, 2026 · 9 revisions

An application which reported to the Business Cockpit with the version 1 adapters keeps almost everything. The business code is untouched, and so is the configuration. What changes is the dependency, and the reason it changes is that the whole application moves from VanillaBP 1 to VanillaBP 2.

So this is a step inside a bigger move rather than a migration of its own. What VanillaBP 2 asks of your application is in its own upgrade guide; this page is only about the cockpit's half.

  1. What stays
    The code and the keys you do not have to touch.
  2. The dependency
    Which artifact replaces the version 1 one, and where it lives now.
  3. The keys which are gone
    Nine of them, one reason each.
  4. What behaves differently
    The six changes you will notice in the cockpit.
  5. Your own way to the cockpit
    What becomes of a publishing bean of version 1.
  6. Where the version 1 documentation lives
    For an application which stays on the old line for a while.

What stays

Your Java code. @UserTaskDetailsProvider, @WorkflowDetailsProvider, @DetailsEvent, the prefilled details objects and BusinessCockpitService are what they were. A method which compiled against version 1 compiles against version 2.

Your configuration. The keys are the ones version 1 read, in the places version 1 read them: vanillabp.cockpit for the whole application, vanillabp.workflow-modules.<id>.cockpit for a workflow module, and the workflow and user task levels below it. A list stays a list and the group hierarchy stays a map of lists. An application upgrades by changing a dependency, and what the cockpit adapter has become inside is nothing it has to know about. Two keys are the exception: template-loader-path is read more strictly than before, and initiator-source is new and mandatory. Both are described under what behaves differently.

Your cockpit server. The REST and Kafka interfaces a workflow module reports on keep their OpenAPI contracts, so a cockpit and a workflow module of different versions still understand each other.

The dependency

Version 1 was an artifact of the cockpit repository, one per BPMS, together with the adapters-commons it depended on. Those artifacts are maintained for the 0.8.x line. They are not part of 0.9.0 any more.

Version 2 has a repository per BPMS, and one artifact per platform in each of them:

BPMS Where it lives
Camunda 7 businesscockpit-camunda7-adapter
Camunda 8 businesscockpit-camunda8-adapter
Process-Engine-API businesscockpit-process-engine-api-adapter

Connecting a workflow module names the artifacts. Each of those wikis has a Migrating from Version 1 page of its own for what changes about that engine, and the Camunda 8 one is worth reading before you deploy, because the first deployment produces a new process version.

Two things follow from the move which have nothing to do with the cockpit as such. Version 1 ran on Spring Boot only, because it depended on VanillaBP 1's spring-boot-support. Version 2 runs on Spring Boot and on Quarkus. And version 2 needs an outbox store in your application, because a report is written before it is sent.

The keys which are gone

Every key not named here is the key it was. These do nothing any more, and on Quarkus a leftover one ends the build with a message saying what became of it:

Version 1 key Why it is gone
rest.log The client logs through SLF4J, so set the logger io.vanillabp.cockpit.bpms.api.v1_1.BpmsApi to DEBUG
rest.additional-get-parameters.<name> It appended query parameters to GET requests, and every report is a POST
rest.retry.* A failed report waits in the outbox and is repeated from there, which vanillabp.outbox.* configures
kafka.group-id-suffix It made a consumer group unique, and the adapter only produces
jwt.hmacSHA256-base64, jwt.cookie.* Version 1 bound them and read them nowhere, and the cockpit server configures its own tokens
group-hierarchy-bean-name The hierarchy is configuration, and which groups may see a module is answered by the WorkflowModuleDetailsProvider bean
workerId It named the instance a report came from, and the adapter takes the host name for that
spring.application.name Only the Camunda 8 exporter path read it, and that path is gone
spring.kafka.consumer.*, camunda.zeebe.kafka-exporter.topic-name Version 1 also consumed a topic a Camunda 8 exporter wrote, and version 2 learns the same from the listeners it puts into the models

Three keys are not version 1's. kafka.bootstrap-servers and kafka.properties.* are what version 1 took from spring.kafka.bootstrap-servers and spring.kafka.producer.*: the adapter builds its own producer now, and does so on both platforms. process-engine-api.remembered-user-tasks comes with the Process-Engine-API integration and does nothing on another engine.

On Spring Boot a key which is gone is simply ignored, so check by hand rather than waiting for a message.

What behaves differently

Every user task appears now. Version 1 reported a user task only when a @UserTaskDetailsProvider matched it and dropped the event otherwise, without saying so. Now every user task of a deployed process is reported, and a provider decides how much the cockpit shows about it rather than whether it shows it. Expect tasks in the cockpit which were not there before, and give them a provider or a template where the BPMN name is not the title you want.

Nothing is lost when the cockpit server is down. Version 1 sent its reports after the transaction committed and forgot them when the send failed. A report is now an outbox entry written in the same transaction as the work which caused it, and repeated until the server takes it. What you see of that is a report arriving a moment later than it used to, and a burst of changes to one task arriving as one report carrying the current state.

A task is read when the report is sent rather than when the event happened. The assignee, the candidates, the dates and the variables a @TaskParam parameter is bound from are read at that point, which is what makes the collapsing above possible.

Who sees a user task is decided once. Version 1 took the assignee, the candidate groups and the excluded users from every update, and an update could give a task to somebody else. Now the report which creates the task in the cockpit sets the assignee, the candidates and the excluded users, and later reports do not change them. Only taking a task over and assigning it in the cockpit still change who has it. admittedUsers is read from every report, as before. If your workflow module handed tasks over by reporting them again, end the task and enter it again instead, for instance with a boundary event. See Organizing user tasks.

Everything is validated while the application starts. Version 1 found a broken setting when the first event arrived. Now the log of the first boot is what you work from, and every gap of the application is named in one boot.

The version attribute of @UserTaskDetailsProvider is read now. Version 1 documented it and never read it, so a method which carried one served every version of your model. It picks the method now, and @WorkflowDetailsProvider has the same attribute. A method which names no version keeps serving every version, so an application which never wrote the attribute reports what it always reported. What a version may name, and what happens where the BPMS reports none, is in Which versions of your model a method serves.

template-loader-path says where its directory is. Version 1 read a path without a prefix as a directory of the file system, and the cockpit server read the same kind of value as a classpath location, so one text meant two things. Now the value carries classpath: or file: in front of it, and one without either ends the boot. The message repeats your value with both prefixes, so an application which wrote /opt/my-application/templates writes file:/opt/my-application/templates. classpath: and classpath*: keep working as they did.

Every report names an initiator, and one new key says who answers it. In version 1 the field was optional and most applications left it empty. Write vanillabp.cockpit.initiator-source: by-application where your details providers set the initiator, or system where a workflow module knows no action a user causes. The key has no default, so an application without it does not start. Under by-application, a report which names nobody fails, and the engine's work fails with it. Old cases keep what they have. Nobody can work out later who started a case which ran without an initiator. That is why you are asked once, instead of the field being switched on quietly. The entry Every report names an initiator, and one new key says who answers it in UPGRADE.md is the short version, and Who caused it is the long one.

Your own way to the cockpit

Version 1 let an application replace the way reports travel. The publishing beans were declared with @ConditionalOnMissingBean, so an application which declared a UserTaskPublishing bean of its own got its own way instead of REST or Kafka.

Version 2 has the same seam, in one place instead of three. A bean of type BusinessCockpitTransport replaces both shipped transports, and it has one method per kind of report: the user task, the workflow and the registration of the workflow module. Version 1 spread those over UserTaskPublishing, WorkflowPublishing and WorkflowModulePublishing, so three beans of version 1 become one class here. A bean which served one of the three and left the others to the shipped way is written by wrapping the shipped transport, which Connecting a workflow module shows.

What such a transport is handed differs from version 1, and in your favour. It is called while an outbox entry is dispatched, so the report has been through the BPMS and through your details provider before you see it. A call which fails is repeated with a backoff instead of losing the report. Version 1 called the publishing bean straight from the engine's thread, and a failure there was yours to survive.

An application which reports its own way configures neither vanillabp.cockpit.rest.base-url nor vanillabp.cockpit.kafka.bootstrap-servers. Both of version 1's keys can go.

Where the version 1 documentation lives

In the history of the cockpit repository. The version 1 adapters were documented in the README files below adapters/, and 0.9.0 removed that directory from the main branch. Read those files at the 0.4.0 tag, the last release which carried them, or on the branch of the 0.8.x line. They are not copied into this wiki, because that would describe an integration which no longer ships.

Releases says which line is which.

Clone this wiki locally