Repository: holunda-io/camunda-bpm-taskpool
Pull request #800 (2023-04-28 16:56:42)

chore(deps): bump camunda-platform-7-mockito from 6.18.0 to 6.19.0
Bumps [camunda-platform-7-mockito](https://github.com/camunda/camunda-platform-7-mockito) from 6.18.0 to 6.19.0.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/camunda/camunda-platform-7-mockito/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.camunda.community.mockito:camunda-platform-7-mockito&package-manager=maven&previous-version=6.18.0&new-version=6.19.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.


codecov[bot]: ## [Codecov](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io) Report
Patch coverage: **`13.59`**% and project coverage change: **`-0.63`** :warning:
> Comparison is base [(`fe9568a`)](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/commit/fe9568ac337ba23cc0611081334165eddb2b9df7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io) 27.22% compared to head [(`41ffff2`)](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io) 26.60%.

<details><summary>Additional details and impacted files</summary>


```diff
@@              Coverage Diff              @@
##             develop     #800      +/-   ##
=============================================
- Coverage      27.22%   26.60%   -0.63%     
- Complexity       395      401       +6     
=============================================
  Files            232      240       +8     
  Lines           6034     6323     +289     
  Branches         475      507      +32     
=============================================
+ Hits            1643     1682      +39     
- Misses          4278     4526     +248     
- Partials         113      115       +2     
```


| [Impacted Files](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io) | Coverage Δ | |
|---|---|---|
| [...kpool/api/process/variable/ProcessVariableValue.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-Y29yZS90YXNrcG9vbC90YXNrcG9vbC1hcGkvc3JjL21haW4va290bGluL2lvL2hvbHVuZGEvY2FtdW5kYS90YXNrcG9vbC9hcGkvcHJvY2Vzcy92YXJpYWJsZS9Qcm9jZXNzVmFyaWFibGVWYWx1ZS5rdA==) | `0.00% <0.00%> (ø)` | |
| [...munda/taskpool/api/task/EngineTaskCommandFilter.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-Y29yZS90YXNrcG9vbC90YXNrcG9vbC1hcGkvc3JjL21haW4va290bGluL2lvL2hvbHVuZGEvY2FtdW5kYS90YXNrcG9vbC9hcGkvdGFzay9FbmdpbmVUYXNrQ29tbWFuZEZpbHRlci5rdA==) | `0.00% <0.00%> (ø)` | |
| [.../core/task/TaskAggregateEngineTaskCommandFilter.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-Y29yZS90YXNrcG9vbC90YXNrcG9vbC1jb3JlL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvcmUvdGFzay9UYXNrQWdncmVnYXRlRW5naW5lVGFza0NvbW1hbmRGaWx0ZXIua3Q=) | `0.00% <0.00%> (ø)` | |
| [.../holunda/polyflow/taskpool/TaskEntityExtensions.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL1Rhc2tFbnRpdHlFeHRlbnNpb25zLmt0) | `0.00% <0.00%> (ø)` | |
| [...skpool/collector/task/TaskEventCollectorService.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL1Rhc2tFdmVudENvbGxlY3RvclNlcnZpY2Uua3Q=) | `3.61% <ø> (ø)` | |
| [...pool/collector/task/TaskServiceCollectorService.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL1Rhc2tTZXJ2aWNlQ29sbGVjdG9yU2VydmljZS5rdA==) | `0.00% <0.00%> (ø)` | |
| [.../assigner/ProcessVariableChangeAssigningService.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL2Fzc2lnbmVyL1Byb2Nlc3NWYXJpYWJsZUNoYW5nZUFzc2lnbmluZ1NlcnZpY2Uua3Q=) | `0.00% <0.00%> (ø)` | |
| [...ask/assigner/ProcessVariableTaskAssignerMapping.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL2Fzc2lnbmVyL1Byb2Nlc3NWYXJpYWJsZVRhc2tBc3NpZ25lck1hcHBpbmcua3Q=) | `0.00% <0.00%> (ø)` | |
| [...ctor/task/assigner/ProcessVariablesTaskAssigner.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL2Fzc2lnbmVyL1Byb2Nlc3NWYXJpYWJsZXNUYXNrQXNzaWduZXIua3Q=) | `0.00% <0.00%> (ø)` | |
| [...sk/enricher/ProcessVariablesTaskCommandEnricher.kt](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io#diff-aW50ZWdyYXRpb24vY2FtdW5kYS1icG0vdGFza3Bvb2wtY29sbGVjdG9yL3NyYy9tYWluL2tvdGxpbi9pby9ob2x1bmRhL3BvbHlmbG93L3Rhc2twb29sL2NvbGxlY3Rvci90YXNrL2VucmljaGVyL1Byb2Nlc3NWYXJpYWJsZXNUYXNrQ29tbWFuZEVucmljaGVyLmt0) | `0.00% <0.00%> (ø)` | |
| ... and [14 more](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io) | |


</details>

[:umbrella: View full report in Codecov by Sentry](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/pull/800?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holunda-io).


Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 163dd227a..475b7c612 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -35,16 +35,16 @@ jobs:
         run: chmod +x ./mvnw
 
       - name: Build with Maven
-        run: ./mvnw clean verify -U -B -T4
+        run: ./mvnw clean verify -U -B -T4 -ntp
 
       - name: Prepare I-Tests
         run: mkdir -p target/jgiven-reports/json
 
       - name: Run I-Tests with Maven
-        run: ./mvnw integration-test failsafe:verify -Pitest -B -T4
+        run: ./mvnw integration-test failsafe:verify -Pitest -B -T4 -ntp
 
       - name: Deploy a new version to central
-        run: ./mvnw deploy -B -DskipTests -Prelease -Dgpg.keyname="${{secrets.GPG_KEYNAME}}" -Dgpg.passphrase="${{secrets.GPG_PASSPHRASE}}"
+        run: ./mvnw deploy -B -ntp -DskipTests -Prelease -Dgpg.keyname="${{secrets.GPG_KEYNAME}}" -Dgpg.passphrase="${{secrets.GPG_PASSPHRASE}}"
         env:
           OSS_CENTRAL_USERNAME: "${{ secrets.SONATYPE_USERNAME }}"
           OSS_CENTRAL_PASSWORD: "${{ secrets.SONATYPE_PASSWORD }}"
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index a3f9f1872..a407f99ee 100755
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1,1 +1,1 @@
-distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
diff --git a/README.md b/README.md
index affe8e6a0..0139a71ca 100755
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 [![stable](https://img.shields.io/badge/lifecycle-STABLE-green.svg)](https://github.com/holisticon#open-source-lifecycle)
-[![Build Status](https://github.com/holunda-io/camunda-bpm-taskpool/workflows/Development%20braches/badge.svg)](https://github.com/holunda-io/camunda-bpm-taskpool/actions)
+[![Master and Snapshot release](https://github.com/holunda-io/camunda-bpm-taskpool/actions/workflows/release.yml/badge.svg)](https://github.com/holunda-io/camunda-bpm-taskpool/actions/workflows/release.yml)
 [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.holunda.polyflow/polyflow-taskpool-dependencies/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.holunda.polyflow/polyflow-taskpool-dependencies/)
 [![Code Coverage](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool/branch/master/graph/badge.svg)](https://codecov.io/gh/holunda-io/camunda-bpm-taskpool)
 [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6e15ca2f4ab64cfe85a736f324136086)](https://www.codacy.com/gh/holunda-io/camunda-bpm-taskpool/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=holunda-io/camunda-bpm-taskpool&amp;utm_campaign=Badge_Grade)
diff --git a/bom/datapool-dependencies/pom.xml b/bom/datapool-dependencies/pom.xml
index a3dcba217..a1c32bd6f 100644
--- a/bom/datapool-dependencies/pom.xml
+++ b/bom/datapool-dependencies/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../parent/pom.xml</relativePath>
   </parent>
 
diff --git a/bom/parent/pom.xml b/bom/parent/pom.xml
index 62134f92f..2de680fd5 100644
--- a/bom/parent/pom.xml
+++ b/bom/parent/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-root</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
@@ -18,7 +18,7 @@
   <url>https://github.com/holunda-io/camunda-bpm-taskpool/</url>
 
   <properties>
-    <springboot.version>2.7.10</springboot.version>
+    <springboot.version>2.7.15</springboot.version>
     <camunda-commons-typed-values.version>7.18.0</camunda-commons-typed-values.version>
 
     <axon-bom.version>4.6.6</axon-bom.version>
@@ -27,9 +27,9 @@
     <axon-gateway-extension.version>1.1.2</axon-gateway-extension.version>
 
     <awaitability.version>4.2.0</awaitability.version>
-    <mockito-kotlin.version>4.1.0</mockito-kotlin.version>
-    <jgiven.version>1.2.5</jgiven.version>
-    <jgiven-kotlin.version>1.2.5.0</jgiven-kotlin.version>
+    <mockito-kotlin.version>5.0.0</mockito-kotlin.version>
+    <jgiven.version>1.3.0</jgiven.version>
+    <jgiven-kotlin.version>1.3.0.0</jgiven-kotlin.version>
 
     <pattern.class.itest>**/*ITest.*</pattern.class.itest>
     <pattern.package.itest>**/itest/**/*.*</pattern.package.itest>
@@ -430,7 +430,7 @@
           <!-- for loading and unpacking artifacts -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
-          <version>3.5.0</version>
+          <version>3.6.0</version>
         </plugin>
 
         <plugin>
@@ -513,7 +513,7 @@
 
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.2</version>
           <configuration>
             <useSystemClassLoader>false</useSystemClassLoader>
             <runOrder>random</runOrder>
@@ -534,7 +534,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-failsafe-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.2</version>
           <executions>
             <execution>
               <goals>
@@ -558,7 +558,7 @@
         <plugin>
           <groupId>org.jetbrains.dokka</groupId>
           <artifactId>dokka-maven-plugin</artifactId>
-          <version>1.8.10</version>
+          <version>1.9.0</version>
           <executions>
             <execution>
               <id>attach-javadocs</id>
@@ -574,7 +574,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>build-helper-maven-plugin</artifactId>
-          <version>3.3.0</version>
+          <version>3.4.0</version>
           <executions>
             <execution>
               <phase>generate-sources</phase>
@@ -594,7 +594,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
-          <version>3.2.1</version>
+          <version>3.3.0</version>
           <executions>
             <execution>
               <id>attach-sources</id>
diff --git a/bom/taskpool-dependencies/pom.xml b/bom/taskpool-dependencies/pom.xml
index e28bd8c10..2c16aabec 100644
--- a/bom/taskpool-dependencies/pom.xml
+++ b/bom/taskpool-dependencies/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../parent/pom.xml</relativePath>
   </parent>
 
diff --git a/core/bus-jackson/pom.xml b/core/bus-jackson/pom.xml
index cca92c5b7..4da605ba7 100755
--- a/core/bus-jackson/pom.xml
+++ b/core/bus-jackson/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../bom/parent/pom.xml</relativePath>
   </parent>
 
diff --git a/core/datapool/datapool-api/pom.xml b/core/datapool/datapool-api/pom.xml
index 1ac955d42..46a6e1c55 100755
--- a/core/datapool/datapool-api/pom.xml
+++ b/core/datapool/datapool-api/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-datapool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-datapool-api</artifactId>
diff --git a/core/datapool/datapool-core/pom.xml b/core/datapool/datapool-core/pom.xml
index c9a5fb099..ebef07c91 100644
--- a/core/datapool/datapool-core/pom.xml
+++ b/core/datapool/datapool-core/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-datapool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-datapool-core</artifactId>
diff --git a/core/datapool/datapool-event/pom.xml b/core/datapool/datapool-event/pom.xml
index 5599af093..cde70462f 100755
--- a/core/datapool/datapool-event/pom.xml
+++ b/core/datapool/datapool-event/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-datapool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-datapool-event</artifactId>
diff --git a/core/datapool/pom.xml b/core/datapool/pom.xml
index 2f50396db..a5f0dca0e 100755
--- a/core/datapool/pom.xml
+++ b/core/datapool/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../bom/parent/pom.xml</relativePath>
   </parent>
 
diff --git a/core/taskpool/pom.xml b/core/taskpool/pom.xml
index d3d2db14e..43e02f17c 100755
--- a/core/taskpool/pom.xml
+++ b/core/taskpool/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../bom/parent/pom.xml</relativePath>
   </parent>
 
diff --git a/core/taskpool/taskpool-api/pom.xml b/core/taskpool/taskpool-api/pom.xml
index 44a939267..3a675fd3c 100755
--- a/core/taskpool/taskpool-api/pom.xml
+++ b/core/taskpool/taskpool-api/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-taskpool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-taskpool-api</artifactId>
diff --git a/core/taskpool/taskpool-core/pom.xml b/core/taskpool/taskpool-core/pom.xml
index 411b7e904..5114fb412 100755
--- a/core/taskpool/taskpool-core/pom.xml
+++ b/core/taskpool/taskpool-core/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-taskpool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-taskpool-core</artifactId>
diff --git a/core/taskpool/taskpool-event/pom.xml b/core/taskpool/taskpool-event/pom.xml
index ac1cdb749..2bb6e367e 100644
--- a/core/taskpool/taskpool-event/pom.xml
+++ b/core/taskpool/taskpool-event/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-taskpool-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-taskpool-event</artifactId>
diff --git a/docs/developer-guide/project-setup.md b/docs/developer-guide/project-setup.md
index 5f45badfa..42e36d70c 100644
--- a/docs/developer-guide/project-setup.md
+++ b/docs/developer-guide/project-setup.md
@@ -60,7 +60,7 @@ You can generate this by executing the following build command:
 ### Build Documentation
 
 We are using MkDocs for generation of a static site documentation and rely on Markdown as much as possible.
-MkDocs is a written in Python 3 and needs to be installed on your machine. For the installation please run the following
+MkDocs is written in Python 3 and needs to be installed on your machine. For the installation please run the following
 command from your command line:
 
 ```bash
diff --git a/docs/reference-guide/components/camunda-taskpool-collector.md b/docs/reference-guide/components/camunda-taskpool-collector.md
index dc1224a9e..1923afb12 100644
--- a/docs/reference-guide/components/camunda-taskpool-collector.md
+++ b/docs/reference-guide/components/camunda-taskpool-collector.md
@@ -15,7 +15,7 @@ received from Camunda BPM Engine (from delegate event listener or from history e
 which is passed over to the Taskpool Collector using internal **Spring eventing** mechanism. The Taskpool
 Collector converts the series of such events into a Taskpool Command - an entity carrying an intent
 of change inside the Taskpool core. Please note that _event_ has another meaning in CQRS/ES systems
-and other components of the Taskpool, but in the context of Taskpool collector an event always originates from
+and other components of the Taskpool, but in the context of Taskpool Collector an event always originates from
 Spring eventing.
 
 ### Features
@@ -25,6 +25,7 @@ Spring eventing.
 - Collection of process variable change events
 - Collection of task events and history events
 - Creation of task engine commands
+- Collection of tasks assignment information
 - Enrichment of task engine commands with process variables
 - Attachment of correlation information to task engine commands
 - Transmission of commands to Axon command bus
@@ -55,7 +56,7 @@ In order to enable collector component, include the Maven dependency to your pro
 
 ```
 
-Then activate the Taskpool collector by providing the annotation on any Spring Configuration:
+Then activate the Taskpool Collector by providing the annotation on any Spring Configuration:
 
 ```java
 @Configuration
@@ -68,7 +69,7 @@ class MyProcessApplicationConfiguration {
 
 ### Event collection
 
-Taskpool Collector registers Spring Event Listener to the following events, fired by Camunda Eventing Engine Plugin:
+By default, Taskpool Collector registers Spring Event Listener to the following events, fired by Camunda Eventing Engine Plugin:
 
 * `DelegateTask` events:
   ** create
@@ -86,6 +87,22 @@ The events are transformed into corresponding commands and passed over to the pr
 is fired using custom listeners only and polyflow components don't rely on that but rather on own implementation of built-in (unskippable) listeners.
 For this purpose, it is important to disable Camunda Platform custom listeners by setting `camunda.bpm.eventing.task` property to `false`.   
 
+During collection of task information, you can control which listeners are registered. By default, all listeners are considered but you can change
+this behaviour by setting values of two properties:
+
+```yaml
+
+polyflow:
+  integration:
+    collector:
+      camunda:
+        task:
+          excludedTaskEventNames: assignment, delete
+          excludedHistoryEventNames: add-identity-link, delete-identity-link
+```
+This particular setting is helpful, if you want to disable assignment in the engine entirely and want to provide you own custom task assignment algorithm or
+use assignment based on process variables (see below for more details).
+
 ### Task commands enrichment
 
 Alongside with attributes received from the Camunda BPM engine, the engine task commands
@@ -126,7 +143,7 @@ A `VariableFilter` can be of the following type:
 Here is an example, how the process variable filter can configure the enrichment:
 
 ```java
-  @Configuration
+@Configuration
 public class MyTaskCollectorConfiguration {
 
   @Bean
@@ -168,6 +185,12 @@ public class MyTaskCollectorConfiguration {
       If you want to implement a custom enrichment, please provide your own implementation of the interface `VariablesEnricher`
       (register a Spring Component of the type) and set the property `polyflow.integration.collector.camunda.task.enricher.type` to `custom`.
 
+!!! warning
+      Avoid using a classic Camunda `TaskListener` which modifies process variables on task creation, since changes of those
+      listeners can't be used during task enrichment. A proper way to modify instance or task variables is to implement an ordered Spring
+      `EventListener` listening on `DelegateTask`, put it before the enricher by providing `@Order(TaskEventCollectorService.ORDER - 80)` and scope the event listener to 
+      the task of your interest using condition: `@EventListener(condition = "#delegateTask.taskDefinitionKey.equals('my-task-key') && #delegateTask.eventName.equals('create')")` 
+
 ### Data Correlation
 
 Apart from task payload attached by the enricher, the so-called _Correlation_ with data entries can
@@ -251,11 +274,11 @@ and the process reaches the task `task_approve_request`, the task will get the f
 
 ### Task Assignment
 
-User task assignment is a core functionality for every process application fostering task oriented work. By default, Taskpool Collector uses
+User task assignment is a core functionality for every process application fostering task-oriented work. By default, Taskpool Collector uses
 information from Camunda User Task and maps that one-to-one to properties of the user task commands. The task attribute
 `assignee`, `candidateUsers` and `candidateGroups` are mapped to the corresponding attributes automatically.
 
-To control the task assignment mode you can configure taskpool collector using application properties. The property 
+To control the task assignment mode you can configure Taskpool Collector using application properties. The property 
 `polyflow.integration.collector.camunda.task.assigner.type` has the following values:
 
 * `no`: No additional assignment takes place, the Camunda task attributes are used (default)
diff --git a/docs/reference-guide/components/view-api-client.md b/docs/reference-guide/components/view-api-client.md
index 27d0569aa..af5b9c400 100644
--- a/docs/reference-guide/components/view-api-client.md
+++ b/docs/reference-guide/components/view-api-client.md
@@ -5,7 +5,7 @@ in order to query the configured views. By doing so, it defines an easy-to-use A
 
 ## Usage
 
-Pleas put the following component to you class path:
+Please put the following component to you class path:
 
 ```xml
 <dependency>
@@ -22,4 +22,12 @@ The components available are:
 * `io.holunda.polyflow.view.ProcessVariableQueryClient`
 * `io.holunda.polyflow.view.TaskQueryClient`
 
+To initialize the client, you need to pass the `queryGateway` to it:
+
+```kotlin
+@Bean
+fun myTaskClient(queryGateway: QueryGateway) = TaskQueryClient(queryGateway)
+
+```
+
 If you are using Kotlin, you might like the extension functions of the `QueryGateway` provided by `io.holunda.polyflow.view.QueryGatewayExt` object.  
diff --git a/docs/reference-guide/components/view-api.md b/docs/reference-guide/components/view-api.md
index 6922ef5ff..af9e7d127 100644
--- a/docs/reference-guide/components/view-api.md
+++ b/docs/reference-guide/components/view-api.md
@@ -21,18 +21,19 @@ and generic query paging and sorting.
 
 The Task API allows to query for tasks handled by the task-pool.
 
-| Query Type                        | Description                                                                                                                                    | Payload types                   | In-Memory | JPA        | Mongo DB |
-|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|-----------|------------|----------|
-| AllTasksQuery                     | Retrieves a list of tasks applying additional filters                                                                                          | List<Task>                      | yes       | yes        | no       |
-| TasksForUserQuery                 | Retrieves a list of tasks accessible by the user and applying additional filters                                                               | List<Task>                      | yes       | yes        | yes      |
-| TasksForGroupQuery                | Retrieves a list of tasks accessible by the user's group and applying additional filters                                                       | List<Task>                      | yes       | yes        | no       |
-| TaskForIdQuery                    | Retrieves a task by id (without any other filters)                                                                                             | Task or null                    | yes       | yes        | yes      |
-| TasksForApplicationQuery          | Retrieves all tasks by given application name (without any further filters)                                                                    | List<Task>                      | yes       | yes        | yes      |
-| AllTasksWithDataEntriesQuery      | Retrieves a list of tasks applying additional filters and correlates result with data entries, if available                                    | List<(Task, List<DataEntry>)    | yes       | incubation | no       |
-| TasksWithDataEntriesForGroupQuery | Retrieves a list of tasks accessible by the user's group and applying additional filters and correlates result with data entries, if available | List<(Task, List<DataEntry>)    | yes       | incubation | no       |
-| TasksWithDataEntriesForUserQuery  | Retrieves a list of tasks accessible by the user and applying additional filters and correlates result with data entries, if available         | List<(Task, List<DataEntry>)    | yes       | incubation | yes      |
-| TaskWithDataEntriesForIdQuery     | Retrieves a task by id and correlates result with data entries, if available                                                                   | (Task, List<DataEntry>) or null | yes       | yes        | yes      |
-| TaskCountByApplicationQuery       | Counts tasks grouped by application names, useful for monitoring                                                                               | List<(ApplicationName, Count)>  | yes       | no         | yes      |
+| Query Type                          | Description                                                                                                                                    | Payload types                   | In-Memory | JPA        | Mongo DB |
+|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|-----------|------------|----------|
+| AllTasksQuery                       | Retrieves a list of tasks applying additional filters                                                                                          | List<Task>                      | yes       | yes        | no       |
+| TasksForUserQuery                   | Retrieves a list of tasks accessible by the user and applying additional filters                                                               | List<Task>                      | yes       | yes        | yes      |
+| TasksForGroupQuery                  | Retrieves a list of tasks accessible by the user's group and applying additional filters                                                       | List<Task>                      | yes       | yes        | no       |
+| TasksForCandidateUserAndGroupQuery  | Retrieves a list of tasks accessible by the user because listed as candidate and the user's group and applying additional filters              | List<Task>                      | yes       | yes        | no       |
+| TaskForIdQuery                      | Retrieves a task by id (without any other filters)                                                                                             | Task or null                    | yes       | yes        | yes      |
+| TasksForApplicationQuery            | Retrieves all tasks by given application name (without any further filters)                                                                    | List<Task>                      | yes       | yes        | yes      |
+| AllTasksWithDataEntriesQuery        | Retrieves a list of tasks applying additional filters and correlates result with data entries, if available                                    | List<(Task, List<DataEntry>)    | yes       | incubation | no       |
+| TasksWithDataEntriesForGroupQuery   | Retrieves a list of tasks accessible by the user's group and applying additional filters and correlates result with data entries, if available | List<(Task, List<DataEntry>)    | yes       | incubation | no       |
+| TasksWithDataEntriesForUserQuery    | Retrieves a list of tasks accessible by the user and applying additional filters and correlates result with data entries, if available         | List<(Task, List<DataEntry>)    | yes       | incubation | yes      |
+| TaskWithDataEntriesForIdQuery       | Retrieves a task by id and correlates result with data entries, if available                                                                   | (Task, List<DataEntry>) or null | yes       | yes        | yes      |
+| TaskCountByApplicationQuery         | Counts tasks grouped by application names, useful for monitoring                                                                               | List<(ApplicationName, Count)>  | yes       | no         | yes      |
  
 
 ### Process Definition API
@@ -90,7 +91,7 @@ for more details. Please note, that not all implementations are implementing thi
 
 ## Filtering, Paging and Sorting
 
-Task API and Data Entries API supports filtering, paging and sorting in queries resulting in multiple results. For Task API these are `AllTasksQuery`, `TasksForGroupQuery`, `TasksForUserQuery`,
+Task API and Data Entries API supports filtering, paging and sorting in queries resulting in multiple results. For Task API these are `AllTasksQuery`, `TasksForGroupQuery`, `TasksForUserQuery`, `TasksForCandidateUserAndGroupQuery`,
 `AllTasksWithDataEntriesQuery`, `TasksWithDataEntriesForGroupQuery`, `TasksWithDataEntriesForUserQuery` and for Data Entries API these are `DataEntriesForUserQuery` and `DataEntriesQuery`. 
 The queries implement the `PageableSortableQuery` interface, allowing to limit the amount of results and provide an optional sorting:
 
@@ -105,16 +106,16 @@ The `page` parameter denotes the page number to deliver (starting with `0`). The
 and the size is set to `Int.MAX`. 
 
 An optional `sort` parameter allows to sort the results by a field attribute. The format of the `sort` string is `<+|->fieldName`, `+fieldName` means sort by `fieldName` ascending,
-`-fieldName` means sort by `fieldName` descending. The field must be a direct member of the result (`Task`, `TaskWithDataEntries` or `DataEntry`) and must be one of the following type:
+`-fieldName` means sort by `fieldName` descending. The field must be a direct member of the result (`Task` for queries on `Task` and `TaskWithDataEntries` or `DataEntry`) and must be one of the following type:
 
 * java.lang.Integer
 * java.lang.String
 * java.util.Date
 * java.time.Instant
 
-To filter the results, you might supply a list of filters. A filter is an expression in format `fieldName<op>value`, where `fieldName` is addressing the attribute of the search result,
+To filter the results, you can supply a list of filters. A filter is an expression in format `fieldName<op>value`, where `fieldName` is addressing the attribute of the search result,
 `<op>` is one of `<`, `=`, `%` and `>` and `value` is a string representation of the values. The `fieldName` can point to an attribute of the result entity itself (`Task`, `TaskWithDataEntries` 
-or `DataEntry`) or point to the attribute inside the payload. To avoid a possible name clash, you must prefix the field name with `task.` if you want to filter on direct attributes of a task,
+or `DataEntry`) or point to the attribute inside the payload. To avoid name clashes, you must prefix the field name with `task` if you want to filter on direct attributes of a task,
 and you must prefix the field name with `data` if you want to filter on direct attributes of a data entry. For example, `task.priority=50` would deliver tasks with priority set to 50,
 and `data.entryType=info.polyflow.Order` will deliver data entries of type `info.polyflow.Order` only.
 
@@ -124,12 +125,21 @@ Following operations are supported:
 |--------|--------------|--------------|-------------------------------------------------------------------|--------------------------------------------------------------------------|----------------------------|------------------------------------|
 | `<`    | Less than    | all, payload | `followUpDate`, `dueDate`                                         | none                                                                     | all, payload               | all, payload                       | 
 | `>`    | Greater than | all, payload | `followUpDate`, `dueDate`                                         | none                                                                     | all, payload               | all, payload                       |
-| `=`    | Equals       | all, payload | payload, `businessKey`, `followUpDate`, `dueDate`                 | `entryId`, `entryType`, `type`, payload, `processingState`, `userStatus` | all, payload               | all, payload                       |
+| `=`    | Equals       | all, payload | payload, `businessKey`, `followUpDate`, `dueDate`, `priority`     | `entryId`, `entryType`, `type`, payload, `processingState`, `userStatus` | all, payload               | all, payload                       |
 | `%`    | Like         | all, payload | `businessKey`, `name`, `description`, `processName`, `textSearch` | none                                                                     | none                       | none                               |
 
 !!! info
-    There are several special reserved filters which can be passed to the task query: `task.processName=<value>` check equality of the process name, `task.processName%<value>` makes a like-search on
-process name, `task.textSearch%some-substring` makes a special OR-combined like-search on task name, task description and task process name. 
+    There are several special reserved filters which can be passed to the task query: `task.processName=<value>` checks equality of the process name, `task.processName%<value>` makes a like-search on
+    process name, `task.textSearch%some-substring` makes a special OR-combined like-search on task name, task description and task process name. 
 
-If the field name has no prefix of above, it is considered as an attribute inside the payload of data entry or enriched variables of a user task. For example, imagine
-you have a data entry with payload attributes `{ "attribute": "value", "another": 45 }`. In order to search for those, just specify `attribute=value` in your filter criteria. 
+If the field name does not have one of the above prefixes, it is considered as an attribute inside the payload of data entry or enriched variables of a user task. For example, imagine
+you have a data entry with payload attributes `{ "attribute": "value", "another": 45 }`. In order to search for those, just specify `attribute=value` in your filter criteria.
+
+Filters are composed with logical AND, meaning that all given filters have to match in order for a task to be included in the result of the query. For example, given the filters
+`task.priority=50` and `foo=bar`, the query result would only contain tasks that have a priority of 50 **and** a payload attribute named foo with the value bar.
+
+!!! warning
+    The [JPA View](view-jpa.md) has a different implementation when applying filters. Filters that target the same attribute are OR-composed before being AND-composed
+    with filters that target other attributes. For example, given the filters `customerName=ABC`, `customerName=DEF` and `task.priority=50`, the filters for the
+    customer name would first get OR-composed before being AND-composed with the task priority filter, resulting in a filtering expression logically equivalent to
+    `(customerName=ABC OR customerName=DEF) AND task.priority=50`.
diff --git a/docs/reference-guide/components/view-jpa.md b/docs/reference-guide/components/view-jpa.md
index 5b39fdce1..1df9bf250 100644
--- a/docs/reference-guide/components/view-jpa.md
+++ b/docs/reference-guide/components/view-jpa.md
@@ -5,7 +5,7 @@ pageId: view-jpa
 ### Purpose
 
 The JPA View is component responsible for creating read-projections of tasks and business data entries. It currently implements
-Datapool View API and Taskpool API and persists the projection as entities and relations in a RDBMS using JPA. It is a useful
+Datapool View API and Taskpool API and persists the projection as entities and relations in a RDBMS using JPA. It is useful
 if the JPA persistence is already used in the project setup.
 
 ### Features
@@ -59,18 +59,29 @@ configuration of this indexing process by the following configuration options:
 
 ```yml
 polyflow.view.jpa:
-  payload-attribute-level-limit: 2
   stored-items: task, data-entry, process-instance, process-definition
+  payload-attribute-level-limit: 2
   data-entry-filters:
     include: myProperty2.myOtherEmbeddedProperty3, myProperty2.myOtherEmbeddedProperty2
 #    exclude: myProperty
+  task-filters:
+    exclude: processVariableWithVeryLongText
+
 ```
 
-In the example below you see the configuration of the limit of keying depth and usage of include/exclude filters of the keys.
+In the example above you see the configuration of the limit of keying depth and usage of include/exclude filters of the keys.
 In addition, the `stored-items` property is holding a set of items to be persisted to the database. The possible values of 
 stored items are: `task`, `data-entry`, `process-instance` and `process-definition`. By setting this property, you can disable
 storage of items not required by your application and save space consumption of your database. The property defaults to `data-entry`.
 
+The attributes `data-entry-filters` and `task-filters` hold `include` / `exclude` lists of property paths which will be taken in 
+consideration during the search index creation.
+
+!!! note
+    Please make sure you understand that the **payload enrichment** performed during collection and **indexing for search** are two different
+    operations. It is perfectly fine to have a large JSON payload attached to the task, but it makes no sense to make the entire payload searchable,
+    at lease using JPA View.
+
 ### Entity Scan
 
 The JPA View utilizes Spring Data repositories and Hibernate entities inside the persistence layer. As a result, it declares a `@EntityScan` 
diff --git a/integration/camunda-bpm/engine-client/pom.xml b/integration/camunda-bpm/engine-client/pom.xml
index 7c511b0cc..136cf2848 100644
--- a/integration/camunda-bpm/engine-client/pom.xml
+++ b/integration/camunda-bpm/engine-client/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-camunda-bpm-engine-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-camunda-bpm-engine-client</artifactId>
diff --git a/integration/camunda-bpm/pom.xml b/integration/camunda-bpm/pom.xml
index 22cad786f..70bbad21e 100644
--- a/integration/camunda-bpm/pom.xml
+++ b/integration/camunda-bpm/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../bom/parent/pom.xml</relativePath>
   </parent>
 
@@ -16,7 +16,7 @@
   <properties>
     <camunda-bpm.version>7.18.0</camunda-bpm.version>
     <camunda-bpm-assert.version>${camunda-bpm.version}</camunda-bpm-assert.version>
-    <camunda-platform-7-mockito.version>6.18.0</camunda-platform-7-mockito.version>
+    <camunda-platform-7-mockito.version>6.19.0</camunda-platform-7-mockito.version>
   </properties>
 
   <modules>
diff --git a/integration/camunda-bpm/springboot-autoconfigure/pom.xml b/integration/camunda-bpm/springboot-autoconfigure/pom.xml
index 27135de31..91c0f4a33 100755
--- a/integration/camunda-bpm/springboot-autoconfigure/pom.xml
+++ b/integration/camunda-bpm/springboot-autoconfigure/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-camunda-bpm-engine-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-camunda-bpm-springboot-autoconfigure</artifactId>
diff --git a/integration/camunda-bpm/springboot-starter/pom.xml b/integration/camunda-bpm/springboot-starter/pom.xml
index 3ac5a9bdd..1aab072eb 100755
--- a/integration/camunda-bpm/springboot-starter/pom.xml
+++ b/integration/camunda-bpm/springboot-starter/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-camunda-bpm-engine-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-camunda-bpm-springboot-starter</artifactId>
diff --git a/integration/camunda-bpm/taskpool-collector/pom.xml b/integration/camunda-bpm/taskpool-collector/pom.xml
index f8fdc2b27..781c4afa6 100755
--- a/integration/camunda-bpm/taskpool-collector/pom.xml
+++ b/integration/camunda-bpm/taskpool-collector/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-camunda-bpm-engine-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-camunda-bpm-taskpool-collector</artifactId>
diff --git a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/CamundaTaskpoolCollectorProperties.kt b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/CamundaTaskpoolCollectorProperties.kt
index 8a930f719..c0a696ce7 100755
--- a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/CamundaTaskpoolCollectorProperties.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/CamundaTaskpoolCollectorProperties.kt
@@ -1,6 +1,7 @@
 package io.holunda.polyflow.taskpool.collector
 
 import io.holunda.polyflow.taskpool.collector.task.assigner.ProcessVariableTaskAssignerMapping
+import org.camunda.bpm.engine.delegate.TaskListener
 import org.springframework.beans.factory.annotation.Value
 import org.springframework.boot.context.properties.ConfigurationProperties
 import org.springframework.boot.context.properties.ConstructorBinding
@@ -69,9 +70,33 @@ data class CamundaTaskCollectorProperties(
    * Properties of task importer.
    */
   @NestedConfigurationProperty
-  val importer: TaskImporterProperties = TaskImporterProperties()
+  val importer: TaskImporterProperties = TaskImporterProperties(),
 
-)
+  /**
+   * List of task events to be excluded from collector. Defaults to empty list, so all events are collected.
+   * Possible values are constants defined in [TaskListener].
+   */
+  val excludedTaskEventNames: List<String> = listOf(),
+
+  /**
+   * List of history events to restrict (HistoricTaskInstanceEventEntity, HistoricIdentityLinkLogEventEntity). Defaults to empty list, so all events are collected.
+   * Possible values are constants defined in [HistoryEventTypes] + "update".
+   */
+  val excludedHistoryEventNames: List<String> = listOf()
+) {
+  /**
+   * Determines if the provided event name should be collected.
+   * @param eventName event name to check.
+   * @return true if not excluded.
+   */
+  fun collectTaskEvent(eventName: String): Boolean = !excludedTaskEventNames.contains(eventName)
+  /**
+   * Determines if the provided event name should be collected.
+   * @param eventName event name to check.
+   * @return true if not excluded.
+   */
+  fun collectHistoryEvent(eventName: String): Boolean = !excludedHistoryEventNames.contains(eventName)
+}
 
 /**
  * Process variable properties.
diff --git a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/ProcessDefinitionService.kt b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/ProcessDefinitionService.kt
index aa0c7c404..61846b701 100644
--- a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/ProcessDefinitionService.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/ProcessDefinitionService.kt
@@ -50,7 +50,15 @@ class ProcessDefinitionService(
       this.processDefinitions.clear()
     }
     this.processDefinitions.addAll(newDefinitions)
-    return newDefinitions.map { it.asCommand(applicationName = collectorProperties.applicationName, formKey = formService.getStartFormKey(it.id)) }
+    return newDefinitions.map { it.asCommand(applicationName = collectorProperties.applicationName, formKey = getStartFormKey(it, formService)) }
+  }
+
+  private fun getStartFormKey(processDefinitionEntity: ProcessDefinitionEntity, formService: FormService): String? {
+    return if (processDefinitionEntity.hasStartFormKey) {
+      formService.getStartFormKey(processDefinitionEntity.id)
+    } else {
+      null
+    }
   }
 
   /**
diff --git a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCollectorConfiguration.kt b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCollectorConfiguration.kt
index 5b4fc1342..9434e7272 100644
--- a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCollectorConfiguration.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCollectorConfiguration.kt
@@ -114,7 +114,7 @@ class TaskCollectorConfiguration(
   /**
    * Constructs the task collector service responsible for collecting Camunda Spring events and building commands out of them.
    */
-  @Bean
+  @Bean(TaskEventCollectorService.NAME)
   fun taskEventCollectorService(repositoryService: RepositoryService) = TaskEventCollectorService(
     camundaTaskpoolCollectorProperties = camundaTaskpoolCollectorProperties,
     repositoryService = repositoryService
diff --git a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCommandProcessor.kt b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCommandProcessor.kt
index 38ff16f83..0aa86f415 100644
--- a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCommandProcessor.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskCommandProcessor.kt
@@ -32,7 +32,7 @@ class TaskCommandProcessor(
       taskAssigner.setAssignment(it)
     }.also { commandToSend ->
       if (logger.isTraceEnabled) {
-        logger.trace("COLLECTOR-008: Sending engine task command: $commandToSend.")
+        logger.trace {"COLLECTOR-008: Sending engine task command: $commandToSend." }
       }
       // enrich and send
       engineTaskCommandSender.send(commandToSend)
diff --git a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskEventCollectorService.kt b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskEventCollectorService.kt
index 5d08ccdc0..2978b57e2 100755
--- a/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskEventCollectorService.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskEventCollectorService.kt
@@ -17,12 +17,13 @@ import org.springframework.core.annotation.Order
  * Collects Camunda events and Camunda historic events (event listener order is {@link TaskEventCollectorService#ORDER}) and emits Commands
  */
 class TaskEventCollectorService(
-  private val camundaTaskpoolCollectorProperties: CamundaTaskpoolCollectorProperties,
+  val camundaTaskpoolCollectorProperties: CamundaTaskpoolCollectorProperties, // must not be private to access in conditions of event handlers
   private val repositoryService: RepositoryService
 ) {
 
 
   companion object : KLogging() {
+    const val NAME = "taskEventCollectorService"
     // high order to be later than all other listeners and work on changed entity
     const val ORDER = Integer.MAX_VALUE - 100
   }
@@ -46,7 +47,7 @@ class TaskEventCollectorService(
    * Fires create command.
    */
   @Order(ORDER)
-  @EventListener(condition = "#task.eventName.equals('create')")
+  @EventListener(condition = "#task.eventName.equals('create') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectTaskEvent('create')")
   fun create(task: DelegateTask): CreateTaskCommand =
     CreateTaskCommand(
       id = task.id,
@@ -70,7 +71,7 @@ class TaskEventCollectorService(
    * Fires complete.
    */
   @Order(ORDER)
-  @EventListener(condition = "#task.eventName.equals('complete')")
+  @EventListener(condition = "#task.eventName.equals('complete') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectTaskEvent('complete')")
   fun complete(task: DelegateTask): CompleteTaskCommand =
     CompleteTaskCommand(
       id = task.id,
@@ -81,17 +82,21 @@ class TaskEventCollectorService(
    * Fires assign command.
    */
   @Order(ORDER)
-  @EventListener(condition = "#task.eventName.equals('assignment')")
+  @EventListener(condition = "#task.eventName.equals('assignment') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectTaskEvent('assignment')")
   fun assign(task: DelegateTask) {
     // this method is intentionally empty to demonstrate that the assign event is captured.
     // we hence rely on historic identity link events to capture assignment via API and via listeners more accurately.
+    // see implementation below
+    if (logger.isTraceEnabled) {
+      logger.trace { "Task ${task.id} is assigned to ${task.assignee}." }
+    }
   }
 
   /**
    * Fires delete command.
    */
   @Order(ORDER)
-  @EventListener(condition = "#task.eventName.equals('delete')")
+  @EventListener(condition = "#task.eventName.equals('delete') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectTaskEvent('delete')")
   fun delete(task: DelegateTask): DeleteTaskCommand =
     DeleteTaskCommand(
       id = task.id,
@@ -103,7 +108,7 @@ class TaskEventCollectorService(
    * Fires update command.
    */
   @Order(ORDER)
-  @EventListener(condition = "#task.eventName.equals('update')")
+  @EventListener(condition = "#task.eventName.equals('update') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectTaskEvent('update')")
   fun update(task: DelegateTask): UpdateAttributeTaskCommand? =
     if (task is TaskEntity) {
       if (task.isAssigneeChange()) {
@@ -122,10 +127,9 @@ class TaskEventCollectorService(
    * into the original intent.
    */
   @Order(ORDER)
-  @EventListener
-  fun update(changeEvent: HistoricTaskInstanceEventEntity): UpdateAttributesHistoricTaskCommand? =
-    when (changeEvent.eventType) {
-      "update" -> UpdateAttributesHistoricTaskCommand(
+  @EventListener(condition = "#changeEvent.eventType.equals('update') && @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectHistoryEvent('update')")
+  fun update(changeEvent: HistoricTaskInstanceEventEntity): UpdateAttributesHistoricTaskCommand =
+      UpdateAttributesHistoricTaskCommand(
         id = changeEvent.taskId,
         description = changeEvent.description,
         dueDate = changeEvent.dueDate,
@@ -137,15 +141,12 @@ class TaskEventCollectorService(
         sourceReference = changeEvent.sourceReference(repositoryService, camundaTaskpoolCollectorProperties.applicationName)
       )
 
-      else -> null
-    }
-
   /**
    * Fires update assignment historic command.
    * This is the only way to detect changes of identity links (candidate user/group change and remove).
    */
   @Order(ORDER)
-  @EventListener
+  @EventListener(condition = "@taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectHistoryEvent('add-identity-link') || @taskEventCollectorService.camundaTaskpoolCollectorProperties.task.collectHistoryEvent('delete-identity-link')")
   fun update(changeEvent: HistoricIdentityLinkLogEventEntity): Any? =
     when {
       // user assignment. Is needed because the assignment out of a listener is undetected otherwise.
diff --git a/integration/camunda-bpm/taskpool-job-sender/pom.xml b/integration/camunda-bpm/taskpool-job-sender/pom.xml
index 020a3e492..75e133f72 100755
--- a/integration/camunda-bpm/taskpool-job-sender/pom.xml
+++ b/integration/camunda-bpm/taskpool-job-sender/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-camunda-bpm-engine-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-camunda-bpm-taskpool-job-sender</artifactId>
diff --git a/integration/camunda-bpm/taskpool-job-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/CamundaJobSenderConfiguration.kt b/integration/camunda-bpm/taskpool-job-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/CamundaJobSenderConfiguration.kt
index 66686c300..cae2ddfa2 100644
--- a/integration/camunda-bpm/taskpool-job-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/CamundaJobSenderConfiguration.kt
+++ b/integration/camunda-bpm/taskpool-job-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/CamundaJobSenderConfiguration.kt
@@ -36,7 +36,6 @@ class CamundaJobSenderConfiguration(
     processEngineConfiguration: ProcessEngineConfigurationImpl,
     @Qualifier(COMMAND_BYTEARRAY_OBJECT_MAPPER)
     objectMapper: ObjectMapper,
-    commandListGateway: CommandListGateway,
     engineTaskCommandAccumulator: EngineTaskCommandAccumulator
   ): EngineTaskCommandSender =
     TxAwareAccumulatingCamundaJobEngineTaskCommandSender(
diff --git a/integration/common/datapool-sender/pom.xml b/integration/common/datapool-sender/pom.xml
index c165bf711..82c96800d 100755
--- a/integration/common/datapool-sender/pom.xml
+++ b/integration/common/datapool-sender/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-common-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-datapool-sender</artifactId>
diff --git a/integration/common/pom.xml b/integration/common/pom.xml
index 86d3e38c3..95362a87c 100755
--- a/integration/common/pom.xml
+++ b/integration/common/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../../bom/parent/pom.xml</relativePath>
   </parent>
 
diff --git a/integration/common/tasklist-url-resolver/pom.xml b/integration/common/tasklist-url-resolver/pom.xml
index 5469daa1e..b70ce8c46 100644
--- a/integration/common/tasklist-url-resolver/pom.xml
+++ b/integration/common/tasklist-url-resolver/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-common-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-tasklist-url-resolver</artifactId>
diff --git a/integration/common/taskpool-sender/pom.xml b/integration/common/taskpool-sender/pom.xml
index 6787b6591..f77540b22 100755
--- a/integration/common/taskpool-sender/pom.xml
+++ b/integration/common/taskpool-sender/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-common-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-taskpool-sender</artifactId>
diff --git a/integration/common/variable-serializer/pom.xml b/integration/common/variable-serializer/pom.xml
index c3e297b35..ccbdc94b8 100755
--- a/integration/common/variable-serializer/pom.xml
+++ b/integration/common/variable-serializer/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-integration-common-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-variable-serializer</artifactId>
diff --git a/pom.xml b/pom.xml
index 2e870cd58..563665431 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
 
   <groupId>io.holunda.polyflow</groupId>
   <artifactId>polyflow-root</artifactId>
-  <version>3.10.1-SNAPSHOT</version>
+  <version>3.14.4-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>POM: ${project.artifactId}</name>
@@ -20,7 +20,7 @@
     <version.java>${java.version}</version.java>
     <version.java>${java.version}</version.java>
 
-    <kotlin.version>1.8.21</kotlin.version>
+    <kotlin.version>1.9.10</kotlin.version>
     <kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
     <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
     <kotlin-logging.version>3.0.5</kotlin-logging.version>
@@ -41,13 +41,13 @@
           <!-- cleaning -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-clean-plugin</artifactId>
-          <version>3.2.0</version>
+          <version>3.3.1</version>
         </plugin>
         <!-- gitflow -->
         <plugin>
           <groupId>com.amashchenko.maven.plugin</groupId>
           <artifactId>gitflow-maven-plugin</artifactId>
-          <version>1.19.0</version>
+          <version>1.20.0</version>
           <configuration>
             <gitFlowConfig>
               <productionBranch>master</productionBranch>
@@ -67,7 +67,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>versions-maven-plugin</artifactId>
-          <version>2.15.0</version>
+          <version>2.16.0</version>
           <configuration>
             <generateBackupPoms>false</generateBackupPoms>
           </configuration>
@@ -79,7 +79,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
-        <version>3.3.0</version>
+        <version>3.4.1</version>
         <executions>
           <execution>
             <id>enforce-maven</id>
@@ -159,7 +159,7 @@
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-gpg-plugin</artifactId>
-            <version>3.0.1</version>
+            <version>3.1.0</version>
             <configuration>
               <!-- pass -Dgpg.keyname=.. and -Dgpg.passphrase=... -->
               <gpgArguments>
diff --git a/view/form-url-resolver/pom.xml b/view/form-url-resolver/pom.xml
index a8a129c7d..67805e164 100644
--- a/view/form-url-resolver/pom.xml
+++ b/view/form-url-resolver/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-form-url-resolver</artifactId>
diff --git a/view/jpa/pom.xml b/view/jpa/pom.xml
index a93b2ca58..50675ed86 100644
--- a/view/jpa/pom.xml
+++ b/view/jpa/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-view-jpa</artifactId>
@@ -233,7 +233,7 @@
               <dependency>
                 <groupId>com.microsoft.sqlserver</groupId>
                 <artifactId>mssql-jdbc</artifactId>
-                <version>12.2.0.jre11</version>
+                <version>12.4.1.jre11</version>
               </dependency>
               <dependency>
                 <groupId>org.postgresql</groupId>
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewTaskService.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewTaskService.kt
index 4ab40c296..ca56faa6e 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewTaskService.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewTaskService.kt
@@ -56,8 +56,22 @@ class JpaPolyflowViewTaskService(
     val criteria = toCriteria(query.filters)
     val taskSpecification = criteria.toTaskSpecification()
     val dataEntrySpecification = criteria.toDataEntrySpecification()
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
-    val userQuery = composeOr(listOf(isAuthorizedFor(authorizedPrincipals), isAssignedTo(query.user.username)))
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+
+    val pageRequest = pageRequest(query.page, query.size, sort)
+
+    val userQuery = if (query.assignedToMeOnly) {
+      isAssignedTo(query.user.username)
+    } else {
+      composeOr(
+        listOf(
+          isAuthorizedFor(authorizedPrincipals),
+          isAssignedTo(query.user.username)
+        )
+      )
+    }
 
     val page = if (taskSpecification != null) {
       taskRepository.findAll(taskSpecification.and(userQuery), pageRequest)
@@ -105,7 +119,10 @@ class JpaPolyflowViewTaskService(
     val criteria = toCriteria(query.filters)
     val taskSpecification = criteria.toTaskSpecification()
     val dataEntrySpecification = criteria.toDataEntrySpecification()
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
 
     val page = if (taskSpecification != null) {
       taskRepository.findAll(taskSpecification.and(taskAuthorizationSpecification), pageRequest)
@@ -144,8 +161,10 @@ class JpaPolyflowViewTaskService(
     val criteria = toCriteria(query.filters)
     val taskSpecification = criteria.toTaskSpecification()
     val dataEntrySpecification = criteria.toDataEntrySpecification()
-
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
 
     val page = if (taskSpecification != null) {
       taskRepository.findAll(taskSpecification, pageRequest)
@@ -182,8 +201,20 @@ class JpaPolyflowViewTaskService(
   override fun query(query: TasksForUserQuery): TaskQueryResult {
     val authorizedPrincipals: Set<AuthorizationPrincipal> = setOf(user(query.user.username)).plus(query.user.groups.map { group(it) })
     val specification = toCriteria(query.filters).toTaskSpecification()
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
-    val userQuery = composeOr(listOf(isAuthorizedFor(authorizedPrincipals), isAssignedTo(query.user.username)))
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
+    val userQuery = if (query.assignedToMeOnly) {
+      isAssignedTo(query.user.username)
+    } else {
+      composeOr(
+        listOf(
+          isAuthorizedFor(authorizedPrincipals),
+          isAssignedTo(query.user.username)
+        )
+      )
+    }
 
     val page = if (specification != null) {
       taskRepository.findAll(specification.and(userQuery), pageRequest)
@@ -206,7 +237,41 @@ class JpaPolyflowViewTaskService(
       )
     )
     val taskSpecification = toCriteria(query.filters).toTaskSpecification()
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
+
+    val page = if (taskSpecification != null) {
+      taskRepository.findAll(taskSpecification.and(authorizationSpecification), pageRequest)
+    } else {
+      taskRepository.findAll(authorizationSpecification, pageRequest)
+    }.map { taskEntity -> taskEntity.toTask(objectMapper) }
+
+    return TaskQueryResult(
+      elements = page.toList(),
+      totalElementCount = page.totalElements.toInt()
+    )
+  }
+
+  @QueryHandler
+  override fun query(query: TasksForCandidateUserAndGroupQuery): TaskQueryResult {
+    val authorizationSpecification =
+      composeAnd(
+        listOf(
+          composeOr(
+            listOf(
+              isAuthorizedFor(setOf(user(query.user.username)).plus(query.user.groups.map { group(it) }.toSet())),
+            )
+          ),
+          isAssigneeSet(query.includeAssigned)
+        )
+      )
+    val taskSpecification = toCriteria(query.filters).toTaskSpecification()
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
 
     val page = if (taskSpecification != null) {
       taskRepository.findAll(taskSpecification.and(authorizationSpecification), pageRequest)
@@ -223,7 +288,10 @@ class JpaPolyflowViewTaskService(
   @QueryHandler
   override fun query(query: AllTasksQuery): TaskQueryResult {
     val specification = toCriteria(query.filters).toTaskSpecification()
-    val pageRequest = pageRequest(query.page, query.size, query.sort)
+    val sort = query.apply {
+      sanitizeSort(Task::class)
+    }.mapTaskSort()
+    val pageRequest = pageRequest(query.page, query.size, sort)
     val page = if (specification != null) {
       taskRepository.findAll(specification, pageRequest)
     } else {
@@ -305,7 +373,7 @@ class JpaPolyflowViewTaskService(
           event.toEntity(
             objectMapper,
             polyflowJpaViewProperties.payloadAttributeLevelLimit,
-            polyflowJpaViewProperties.dataEntryJsonPathFilters()
+            polyflowJpaViewProperties.taskJsonPathFilters()
           )
         )
         emitTaskUpdate(updated)
@@ -399,7 +467,7 @@ class JpaPolyflowViewTaskService(
             objectMapper,
             entity,
             polyflowJpaViewProperties.payloadAttributeLevelLimit,
-            polyflowJpaViewProperties.dataEntryJsonPathFilters()
+            polyflowJpaViewProperties.taskJsonPathFilters()
           )
         )
         emitTaskUpdate(updated)
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/PolyflowJpaViewProperties.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/PolyflowJpaViewProperties.kt
index a2d808874..e9ce9b051 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/PolyflowJpaViewProperties.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/PolyflowJpaViewProperties.kt
@@ -26,7 +26,14 @@ data class PolyflowJpaViewProperties(
    * Filters for the paths for indexing.
    */
   @NestedConfigurationProperty
-  private val dataEntryFilters: PayloadAttributeFilterPaths = PayloadAttributeFilterPaths()
+  private val dataEntryFilters: PayloadAttributeFilterPaths = PayloadAttributeFilterPaths(),
+
+  /**
+   * Filters for the path for indexing.
+   */
+  @NestedConfigurationProperty
+  private val taskFilters: PayloadAttributeFilterPaths = PayloadAttributeFilterPaths()
+
 ) {
   /**
    * Extracts JSON path filters out of the properties.
@@ -34,6 +41,14 @@ data class PolyflowJpaViewProperties(
   fun dataEntryJsonPathFilters(): List<Pair<JsonPathFilterFunction, FilterType>> {
     return this.dataEntryFilters.include.map { eqInclude(it) }.plus(this.dataEntryFilters.exclude.map { eqExclude(it) })
   }
+
+  /**
+   * Extracts JSON path filters out of the properties.
+   */
+  fun taskJsonPathFilters(): List<Pair<JsonPathFilterFunction, FilterType>> {
+    return this.taskFilters.include.map { eqInclude(it) }.plus(this.taskFilters.exclude.map { eqExclude(it) })
+  }
+
 }
 
 /**
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/SpecificationExt.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/SpecificationExt.kt
index bcff2603c..81a3b9081 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/SpecificationExt.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/SpecificationExt.kt
@@ -20,6 +20,7 @@ import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasDueDateBefo
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasFollowUpDate
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasFollowUpDateAfter
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasFollowUpDateBefore
+import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasPriority
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasProcessName
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.hasTaskPayloadAttribute
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.likeBusinessKey
@@ -27,8 +28,10 @@ import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.likeDescriptio
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.likeName
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.likeProcessName
 import io.holunda.polyflow.view.jpa.task.TaskRepository.Companion.likeTextSearch
+import io.holunda.polyflow.view.query.PageableSortableQuery
 import org.springframework.data.domain.PageRequest
 import org.springframework.data.domain.Sort
+import org.springframework.data.domain.Sort.Direction
 import org.springframework.data.jpa.domain.Specification
 import org.springframework.data.jpa.domain.Specification.where
 import java.time.Instant
@@ -75,7 +78,12 @@ fun pageRequest(page: Int, size: Int, sort: String?): PageRequest {
   val sortCriteria = if (sort.isNullOrBlank()) {
     null
   } else {
-    Sort.by(Sort.Direction.fromOptionalString(sort.substring(0, 1)).orElse(Sort.DEFAULT_DIRECTION), sort.substring(1))
+    val direction = if (sort.substring(0, 1) == "+") {
+      Direction.ASC
+    } else {
+      Direction.DESC
+    }
+    Sort.by(direction, sort.substring(1))
   }
   return if (sortCriteria != null) {
     PageRequest.of(page, size, sortCriteria)
@@ -84,37 +92,81 @@ fun pageRequest(page: Int, size: Int, sort: String?): PageRequest {
   }
 }
 
+/**
+ * Map sort string from the view API to implementation sort of the entities.
+ */
+fun PageableSortableQuery.mapTaskSort(): String {
+  return if (this.sort == null) {
+    // no sort is specified, we don't want unsorted results.
+    "-${TaskEntity::createdDate.name}"
+  } else {
+    val direction = sort!!.substring(0, 1)
+    val field = sort!!.substring(1)
+    return when (field) {
+      Task::name.name -> TaskEntity::name.name
+      Task::description.name -> TaskEntity::description.name
+      Task::assignee.name -> TaskEntity::assignee.name
+      Task::createTime.name -> TaskEntity::createdDate.name
+      Task::dueDate.name -> TaskEntity::dueDate.name
+      Task::followUpDate.name -> TaskEntity::followUpDate.name
+      Task::owner.name -> TaskEntity::owner.name
+      Task::priority.name -> TaskEntity::priority.name
+      Task::formKey.name -> TaskEntity::formKey.name
+      Task::businessKey.name -> TaskEntity::businessKey.name
+      Task::id.name -> TaskEntity::taskId.name
+      Task::taskDefinitionKey.name -> TaskEntity::taskDefinitionKey.name
+      else -> throw IllegalArgumentException("'$field' is not supported for sorting in JPA View")
+    }.let { "$direction$it" }
+  }
+}
+
 
 /**
  * Specification for query on task attributes.
  */
 internal fun List<Criterion>.toTaskAttributeSpecification(): Specification<TaskEntity>? {
-  val relevant = this.filterIsInstance<Criterion.TaskCriterion>().map { it.toTaskSpecification() }
-  return composeAnd(relevant)
+  val relevant = this.filterIsInstance<Criterion.TaskCriterion>()
+  // compose criteria with same name with OR and criteria with different names with AND
+  val relevantByName = relevant.groupBy { it.name }
+  val orComposedByName = relevantByName.map { (_, criteria) -> composeOr(criteria.map { it.toTaskSpecification() }) }
+
+  return composeAnd(orComposedByName)
 }
 
 /**
  * Specification for query on data entry attributes.
  */
 internal fun List<Criterion>.toDataEntryAttributeSpecification(): Specification<DataEntryEntity>? {
-  val relevant = this.filterIsInstance<Criterion.DataEntryCriterion>().map { it.toDataEntrySpecification() }
-  return composeAnd(relevant)
+  val relevant = this.filterIsInstance<Criterion.DataEntryCriterion>()
+  // compose criteria with same name with OR and criteria with different names with AND
+  val relevantByName = relevant.groupBy { it.name }
+  val orComposedByName = relevantByName.map { (_, criteria) -> composeOr(criteria.map { it.toDataEntrySpecification() }) }
+
+  return composeAnd(orComposedByName)
 }
 
 /**
  * Specification on payload.
  */
 internal fun List<Criterion>.toDataEntryPayloadSpecification(): Specification<DataEntryEntity>? {
-  val relevant = this.filterIsInstance<Criterion.PayloadEntryCriterion>().map { it.toDataEntrySpecification() }
-  return composeAnd(relevant)
+  val relevant = this.filterIsInstance<Criterion.PayloadEntryCriterion>()
+  // compose criteria with same name with OR and criteria with different names with AND
+  val relevantByName = relevant.groupBy { it.name }
+  val orComposedByName = relevantByName.map { (_, criteria) -> criteria.toOrDataEntrySpecification() }
+
+  return composeAnd(orComposedByName)
 }
 
 /**
  * Specification on payload.
  */
 internal fun List<Criterion>.toTaskPayloadSpecification(): Specification<TaskEntity>? {
-  val relevant = this.filterIsInstance<Criterion.PayloadEntryCriterion>().map { it.toTaskSpecification() }
-  return composeAnd(relevant)
+  val relevant = this.filterIsInstance<Criterion.PayloadEntryCriterion>()
+  // compose criteria with same name with OR and criteria with different names with AND
+  val relevantByName = relevant.groupBy { it.name }
+  val orComposedByName = relevantByName.map { (_, criteria) -> criteria.toOrTaskSpecification() }
+
+  return composeAnd(orComposedByName)
 }
 
 
@@ -129,9 +181,11 @@ internal fun Criterion.TaskCriterion.toTaskSpecification(): Specification<TaskEn
         Task::businessKey.name -> hasBusinessKey(this.value)
         Task::dueDate.name -> hasDueDate(Instant.parse(this.value))
         Task::followUpDate.name -> hasFollowUpDate(Instant.parse(this.value))
+        Task::priority.name -> hasPriority(this.value.toInt())
         else -> throw IllegalArgumentException("JPA View found unsupported task attribute for equals comparison: ${this.name}.")
       }
     }
+
     LIKE -> {
       when (this.name) {
         "textSearch" -> likeTextSearch(this.value)
@@ -142,6 +196,7 @@ internal fun Criterion.TaskCriterion.toTaskSpecification(): Specification<TaskEn
         else -> throw IllegalArgumentException("JPA View found unsupported task attribute for like comparison: ${this.name}.")
       }
     }
+
     LESS -> {
       when (this.name) {
         Task::dueDate.name -> hasDueDateBefore(Instant.parse(this.value))
@@ -149,6 +204,7 @@ internal fun Criterion.TaskCriterion.toTaskSpecification(): Specification<TaskEn
         else -> throw IllegalArgumentException("JPA View found unsupported task attribute for < comparison: ${this.name}.")
       }
     }
+
     GREATER -> {
       when (this.name) {
         Task::dueDate.name -> hasDueDateAfter(Instant.parse(this.value))
@@ -156,18 +212,21 @@ internal fun Criterion.TaskCriterion.toTaskSpecification(): Specification<TaskEn
         else -> throw IllegalArgumentException("JPA View found unsupported task attribute for > comparison: ${this.name}.")
       }
     }
+
     else -> throw IllegalArgumentException("JPA View found unsupported comparison ${this.operator} for attribute ${this.name}.")
   }
 }
 
 /**
- * Creates JPA Specification for query of payload attributes based on JSON paths.
+ * Creates JPA Specification for query of payload attributes based on JSON paths. All criteria must have the same path
+ * and will be composed by the logical OR operator.
  */
-internal fun Criterion.PayloadEntryCriterion.toTaskSpecification(): Specification<TaskEntity> {
-  return when (this.operator) {
-    EQUALS -> hasTaskPayloadAttribute(this.name, this.value)
-    else -> throw IllegalArgumentException("JPA View currently supports only equals as operator for filtering of payload attributes.")
-  }
+internal fun List<Criterion.PayloadEntryCriterion>.toOrTaskSpecification(): Specification<TaskEntity> {
+  require(this.isNotEmpty()) { "List of criteria must not be empty." }
+  require(this.all { it.operator == EQUALS }) { "JPA View currently supports only equals as operator for filtering of payload attributes." }
+  require(this.distinctBy { it.name }.size == 1) { "All criteria must have the same path." }
+
+  return hasTaskPayloadAttribute(this.first().name, this.map { it.value })
 }
 
 /**
@@ -185,13 +244,15 @@ internal fun Criterion.DataEntryCriterion.toDataEntrySpecification(): Specificat
 }
 
 /**
- * Creates JPA Specification for query of payload attributes based on JSON paths.
+ * Creates JPA Specification for query of payload attributes based on JSON paths. All criteria must have the same path
+ * and will be composed by the logical OR operator.
  */
-internal fun Criterion.PayloadEntryCriterion.toDataEntrySpecification(): Specification<DataEntryEntity> {
-  return when (this.operator) {
-    EQUALS -> hasDataEntryPayloadAttribute(this.name, this.value)
-    else -> throw IllegalArgumentException("JPA View currently supports only equals as operator for filtering of payload attributes.")
-  }
+internal fun List<Criterion.PayloadEntryCriterion>.toOrDataEntrySpecification(): Specification<DataEntryEntity> {
+  require(this.isNotEmpty()) { "List of criteria must not be empty." }
+  require(this.all { it.operator == EQUALS }) { "JPA View currently supports only equals as operator for filtering of payload attributes." }
+  require(this.distinctBy { it.name }.size == 1) { "All criteria must have the same path." }
+
+  return hasDataEntryPayloadAttribute(this.first().name, this.map { it.value })
 }
 
 
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryEntity.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryEntity.kt
index a058e6316..d37f65b96 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryEntity.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryEntity.kt
@@ -2,6 +2,8 @@ package io.holunda.polyflow.view.jpa.data
 
 
 import io.holunda.polyflow.view.jpa.payload.PayloadAttribute
+import org.hibernate.annotations.Fetch
+import org.hibernate.annotations.FetchMode
 import java.time.Instant
 import javax.persistence.*
 
@@ -13,19 +15,19 @@ import javax.persistence.*
 class DataEntryEntity(
   @EmbeddedId
   var dataEntryId: DataEntryId,
-  @Column(name = "TYPE", nullable = false)
+  @Column(name = "TYPE", length = 255, nullable = false)
   var type: String,
-  @Column(name = "NAME", nullable = false)
+  @Column(name = "NAME", length = 255, nullable = false)
   var name: String,
-  @Column(name = "APPLICATION_NAME", nullable = false)
+  @Column(name = "APPLICATION_NAME", length = 64, nullable = false)
   var applicationName: String,
-  @Column(name = "FORM_KEY")
+  @Column(name = "FORM_KEY", length = 64, nullable = true)
   var formKey: String? = null,
   @Column(name = "REVISION")
   var revision: Long = 0L,
   @Embedded
   var state: DataEntryStateEmbeddable,
-  @Column(name = "DESCRIPTION", length = 2048)
+  @Column(name = "DESCRIPTION", nullable = true, length = 2048)
   var description: String? = null,
 
   @Column(name = "DATE_CREATED", nullable = false)
@@ -58,6 +60,7 @@ class DataEntryEntity(
 
 
   @OneToMany(mappedBy = "dataEntry", orphanRemoval = true, cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
+  @Fetch(FetchMode.SELECT)
   var protocol: MutableList<ProtocolElement> = mutableListOf(),
 
   @Column(name = "PAYLOAD")
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryId.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryId.kt
index a6e143968..3228cde99 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryId.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryId.kt
@@ -10,9 +10,9 @@ import javax.persistence.Embeddable
  */
 @Embeddable
 class DataEntryId(
-  @Column(name = "ENTRY_ID", nullable = false)
+  @Column(name = "ENTRY_ID", length = 64, nullable = false)
   var entryId: String,
-  @Column(name = "ENTRY_TYPE", nullable = false)
+  @Column(name = "ENTRY_TYPE", length = 128, nullable = false)
   var entryType: String
 ) : Serializable {
 
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepository.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepository.kt
index 1c6380ae2..2d7354686 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepository.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepository.kt
@@ -84,20 +84,26 @@ interface DataEntryRepository : CrudRepository<DataEntryEntity, DataEntryId>, Jp
       }
 
     /**
-     * Specification for checking the payload attribute.
+     * Specification for checking the payload attribute. If multiple values are given, one of them must match.
+     * payload.name = ? AND (payload.value = ? OR payload.value = ? OR ...)
      */
-    fun hasDataEntryPayloadAttribute(name: String, value: String): Specification<DataEntryEntity> =
-      Specification { dataEntry, _, builder ->
+    fun hasDataEntryPayloadAttribute(name: String, values: List<String>): Specification<DataEntryEntity> =
+      Specification { dataEntry, query, builder ->
+        query.distinct(true)
         val join = dataEntry.join<DataEntryEntity, Set<PayloadAttribute>>(DataEntryEntity::payloadAttributes.name)
         val pathEquals = builder.equal(
           join.get<String>(PayloadAttribute::path.name),
           name
         )
-        val valueEquals = builder.equal(
-          join.get<String>(PayloadAttribute::value.name),
-          value
-        )
-        builder.and(pathEquals, valueEquals)
+
+        val valueAnyOf = values.map {
+          builder.equal(
+            join.get<String>(PayloadAttribute::value.name),
+            it
+          )
+        }.let { builder.or(*it.toTypedArray()) }
+
+        builder.and(pathEquals, valueAnyOf)
       }
 
     /**
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryStateEmbeddable.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryStateEmbeddable.kt
index 8a9ef3e05..12e5cd1e3 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryStateEmbeddable.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryStateEmbeddable.kt
@@ -10,9 +10,9 @@ import javax.persistence.Embeddable
  */
 @Embeddable
 class DataEntryStateEmbeddable(
-  @Column(name = "PROCESSING_TYPE", nullable = false)
+  @Column(name = "PROCESSING_TYPE", length = 64, nullable = false)
   var processingType: String,
-  @Column(name = "STATE", nullable = false)
+  @Column(name = "STATE", length = 64, nullable = false)
   var state: String
 ) : Serializable {
   companion object {
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/ProtocolElement.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/ProtocolElement.kt
index 7b2de164f..129b45975 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/ProtocolElement.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/ProtocolElement.kt
@@ -11,18 +11,18 @@ import javax.persistence.*
 @Table(name = "PLF_DATA_ENTRY_PROTOCOL")
 class ProtocolElement(
   @Id
-  @Column(name = "ID")
+  @Column(name = "ID", length = 64, nullable = false)
   var id: String = UUID.randomUUID().toString(),
 
   @Column(name = "TIME", nullable = false)
   var time: Instant = Instant.now(),
   @Embedded
   var state: DataEntryStateEmbeddable,
-  @Column(name = "USERNAME", nullable = true)
+  @Column(name = "USERNAME", length = 64, nullable = true)
   var username: String? = null,
-  @Column(name = "LOG_MESSAGE", nullable = true)
+  @Column(name = "LOG_MESSAGE", length = 2048, nullable = true)
   var logMessage: String? = null,
-  @Column(name = "LOG_DETAILS", nullable = true)
+  @Column(name = "LOG_DETAILS", length = 2048, nullable = true)
   var logDetails: String? = null,
 
   @ManyToOne
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessDefinitionEntity.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessDefinitionEntity.kt
index 04b1cb1f1..f1b9fc495 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessDefinitionEntity.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessDefinitionEntity.kt
@@ -9,15 +9,15 @@ import javax.persistence.*
 @Table(name = "PLF_PROC_DEF")
 class ProcessDefinitionEntity(
   @Id
-  @Column(name = "PROC_DEF_ID")
+  @Column(name = "PROC_DEF_ID", length = 255)
   var processDefinitionId: String,
-  @Column(name = "PROC_DEF_KEY", nullable = false)
+  @Column(name = "PROC_DEF_KEY", length = 255, nullable = false)
   var processDefinitionKey: String,
   @Column(name = "PROC_DEF_VERSION", nullable = false)
   var processDefinitionVersion: Int,
-  @Column(name = "APPLICATION_NAME", nullable = false)
+  @Column(name = "APPLICATION_NAME", length = 64, nullable = false)
   var applicationName: String,
-  @Column(name = "NAME", nullable = false)
+  @Column(name = "NAME", length = 255, nullable = false)
   var name: String,
   @Column(name = "VERSION_TAG")
   var versionTag: String? = null,
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessInstanceEntity.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessInstanceEntity.kt
index c3d5222e8..95e38d83a 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessInstanceEntity.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessInstanceEntity.kt
@@ -10,23 +10,23 @@ import javax.persistence.*
 @Table(name = "PLF_PROC_INSTANCE")
 class ProcessInstanceEntity(
   @Id
-  @Column(name = "INSTANCE_ID", nullable = true)
+  @Column(name = "INSTANCE_ID", length = 64, nullable = true)
   var processInstanceId: String,
-  @Column(name = "BUSINESS_KEY", nullable = true)
+  @Column(name = "BUSINESS_KEY", length = 64, nullable = true)
   var businessKey: String?,
-  @Column(name = "SUPER_INSTANCE_ID", nullable = true)
+  @Column(name = "SUPER_INSTANCE_ID", length = 64, nullable = true)
   var superInstanceId: String?,
-  @Column(name = "START_ACTIVITY_ID", nullable = true)
+  @Column(name = "START_ACTIVITY_ID", length = 64, nullable = true)
   var startActivityId: String?,
-  @Column(name = "END_ACTIVITY_ID", nullable = true)
+  @Column(name = "END_ACTIVITY_ID", length = 64, nullable = true)
   var endActivityId: String?,
-  @Column(name = "DELETE_REASON", nullable = true)
+  @Column(name = "DELETE_REASON", length = 2048, nullable = true)
   var deleteReason: String?,
-  @Column(name = "START_USER_ID", nullable = true)
+  @Column(name = "START_USER_ID", length = 64, nullable = true)
   var startUserId: String?,
   @Embedded
   var sourceReference: SourceReferenceEmbeddable,
-  @Column(name = "RUN_STATE", nullable = false)
+  @Column(name = "RUN_STATE", length = 64, nullable = false)
   @Enumerated(EnumType.STRING)
   var state: ProcessInstanceState
 )
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/SourceReferenceEmbeddable.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/SourceReferenceEmbeddable.kt
index 72dddecbc..50f177bba 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/SourceReferenceEmbeddable.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/SourceReferenceEmbeddable.kt
@@ -9,21 +9,21 @@ import javax.persistence.Embeddable
  */
 @Embeddable
 class SourceReferenceEmbeddable(
-  @Column(name = "SOURCE_INSTANCE_ID", nullable = false)
+  @Column(name = "SOURCE_INSTANCE_ID", length = 64, nullable = false)
   var instanceId: String,
-  @Column(name = "SOURCE_EXECUTION_ID", nullable = false)
+  @Column(name = "SOURCE_EXECUTION_ID", length = 64, nullable = false)
   var executionId: String,
-  @Column(name = "SOURCE_DEF_ID", nullable = false)
+  @Column(name = "SOURCE_DEF_ID", length = 64, nullable = false)
   var definitionId: String,
-  @Column(name = "SOURCE_DEF_KEY", nullable = false)
+  @Column(name = "SOURCE_DEF_KEY", length = 64, nullable = false)
   var definitionKey: String,
-  @Column(name = "SOURCE_NAME", nullable = false)
+  @Column(name = "SOURCE_NAME", length = 255, nullable = false)
   var name: String,
-  @Column(name = "APPLICATION_NAME", nullable = false)
+  @Column(name = "APPLICATION_NAME", length = 64, nullable = false)
   var applicationName: String,
-  @Column(name = "SOURCE_TENANT_ID", nullable = true)
+  @Column(name = "SOURCE_TENANT_ID", length = 64, nullable = true)
   var tenantId: String? = null,
-  @Column(name = "SOURCE_TYPE", nullable = false)
+  @Column(name = "SOURCE_TYPE", length = 64, nullable = false)
   var sourceType: String
 ) : Serializable {
 
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntity.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntity.kt
index 53e5165a4..cf62c5f8c 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntity.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntity.kt
@@ -14,11 +14,11 @@ import javax.persistence.*
 @Table(name = "PLF_TASK")
 class TaskEntity(
   @Id
-  @Column(name = "TASK_ID", nullable = false)
+  @Column(name = "TASK_ID", length = 64, nullable = false)
   var taskId: String,
   @Column(name = "TASK_DEF_KEY", nullable = false)
   var taskDefinitionKey: String,
-  @Column(name = "NAME", nullable = false)
+  @Column(name = "NAME", length = 128, nullable = false)
   var name: String,
   @Column(name = "PRIORITY")
   var priority: Int,
@@ -49,21 +49,21 @@ class TaskEntity(
     ]
   )
   var payloadAttributes: MutableSet<PayloadAttribute> = mutableSetOf(),
-  @Column(name = "BUSINESS_KEY")
+  @Column(name = "BUSINESS_KEY", length = 255, nullable = true)
   var businessKey: String? = null,
-  @Column(name = "DESCRIPTION", length = 2048)
+  @Column(name = "DESCRIPTION", length = 2048, nullable = true)
   var description: String? = null,
   @Column(name = "FORM_KEY")
   var formKey: String? = null,
   @Column(name = "DATE_CREATED", nullable = false)
   var createdDate: Instant = Instant.now(),
-  @Column(name = "DATE_DUE")
+  @Column(name = "DATE_DUE", nullable = true)
   var dueDate: Instant? = null,
-  @Column(name = "DATE_FOLLOW_UP")
+  @Column(name = "DATE_FOLLOW_UP", nullable = true)
   var followUpDate: Instant? = null,
-  @Column(name = "OWNER_ID")
+  @Column(name = "OWNER_ID", length = 64, nullable = true)
   var owner: String? = null,
-  @Column(name = "ASSIGNEE_ID")
+  @Column(name = "ASSIGNEE_ID", length = 64, nullable = true)
   var assignee: String? = null,
   @Column(name = "PAYLOAD")
   @Lob
diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepository.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepository.kt
index 29ea7e690..2cb069c33 100644
--- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepository.kt
+++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepository.kt
@@ -2,7 +2,6 @@ package io.holunda.polyflow.view.jpa.task
 
 import io.holunda.polyflow.view.jpa.auth.AuthorizationPrincipal
 import io.holunda.polyflow.view.jpa.composeOr
-import io.holunda.polyflow.view.jpa.data.DataEntryEntity
 import io.holunda.polyflow.view.jpa.payload.PayloadAttribute
 import io.holunda.polyflow.view.jpa.process.SourceReferenceEmbeddable
 import org.springframework.data.jpa.domain.Specification
@@ -86,6 +85,17 @@ interface TaskRepository : CrudRepository<TaskEntity, String>, JpaSpecificationE
         )
       }
 
+    /**
+     * Specification for checking the priority.
+     */
+    fun hasPriority(priority: Int): Specification<TaskEntity> =
+      Specification { task, _, builder ->
+        builder.equal(
+          task.get<Int>(TaskEntity::priority.name),
+          priority
+        )
+      }
+
     /**
      * Specification for checking the due date.
      */
@@ -225,20 +235,26 @@ interface TaskRepository : CrudRepository<TaskEntity, String>, JpaSpecificationE
         .or(likeProcessName(pattern))
 
     /**
-     * Specification for checking the payload attribute.
+     * Specification for checking the payload attribute of a task. If multiple values are given, one of them must match.
+     * payload.name = ? AND (payload.value = ? OR payload.value = ? OR ...)
      */
-    fun hasTaskPayloadAttribute(name: String, value: String): Specification<TaskEntity> =
-      Specification { task, _, builder ->
-        val join = task.join<DataEntryEntity, Set<PayloadAttribute>>(TaskEntity::payloadAttributes.name)
+    fun hasTaskPayloadAttribute(name: String, values: List<String>): Specification<TaskEntity> =
+      Specification { task, query, builder ->
+        query.distinct(true)
+        val join = task.join<TaskEntity, Set<PayloadAttribute>>(TaskEntity::payloadAttributes.name)
         val pathEquals = builder.equal(
           join.get<String>(PayloadAttribute::path.name),
           name
         )
-        val valueEquals = builder.equal(
-          join.get<String>(PayloadAttribute::value.name),
-          value
-        )
-        builder.and(pathEquals, valueEquals)
+
+        val valueAnyOf = values.map {
+          builder.equal(
+            join.get<String>(PayloadAttribute::value.name),
+            it
+          )
+        }.let { builder.or(*it.toTypedArray()) }
+
+        builder.and(pathEquals, valueAnyOf)
       }
   }
 }
diff --git a/view/mongo/pom.xml b/view/mongo/pom.xml
index cd5c21e90..471588d36 100755
--- a/view/mongo/pom.xml
+++ b/view/mongo/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-view-mongo</artifactId>
diff --git a/view/pom.xml b/view/pom.xml
index fdafa474f..f00fef936 100644
--- a/view/pom.xml
+++ b/view/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
     <relativePath>../bom/parent/pom.xml</relativePath>
   </parent>
 
diff --git a/view/simple/pom.xml b/view/simple/pom.xml
index 665384539..438d5c059 100755
--- a/view/simple/pom.xml
+++ b/view/simple/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-view-simple</artifactId>
diff --git a/view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/service/SimpleTaskPoolService.kt b/view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/service/SimpleTaskPoolService.kt
index 380ebb854..8767b39ae 100755
--- a/view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/service/SimpleTaskPoolService.kt
+++ b/view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/service/SimpleTaskPoolService.kt
@@ -106,7 +106,7 @@ class SimpleTaskPoolService(
 
     val predicates = createTaskPredicates(toCriteria(query.filters))
 
-    val filtered = tasks.values.filter { TasksForUserQuery(query.user).applyFilter(it) }
+    val filtered = tasks.values.filter { TasksForUserQuery(user = query.user, assignedToMeOnly = query.assignedToMeOnly ).applyFilter(it) }
       .asSequence()
       .map { task -> TaskWithDataEntries.correlate(task, dataEntries) }
       .filter { filterByPredicate(it, predicates) }
@@ -185,6 +185,15 @@ class SimpleTaskPoolService(
     return queryForTasks(query)
   }
 
+  /**
+   * Retrieves a list of all user tasks for current user's groups and current user being member of candidate users.
+   */
+  @QueryHandler
+  override fun query(query: TasksForCandidateUserAndGroupQuery): TaskQueryResult {
+    return queryForTasks(query)
+  }
+
+
   /**
    * Retrieves a list of all user tasks.
    */
@@ -361,6 +370,7 @@ class SimpleTaskPoolService(
   private fun updateFilteredQueryQuery(taskId: String) {
     queryUpdateEmitter.updateMapFilterQuery(tasks, taskId, TasksForUserQuery::class.java)
     queryUpdateEmitter.updateMapFilterQuery(tasks, taskId, TasksForGroupQuery::class.java)
+    queryUpdateEmitter.updateMapFilterQuery(tasks, taskId, TasksForCandidateUserAndGroupQuery::class.java)
     queryUpdateEmitter.updateMapFilterQuery(tasks, taskId, AllTasksQuery::class.java)
 
     tasks[taskId]
diff --git a/view/view-api-client/pom.xml b/view/view-api-client/pom.xml
index d25e6cb8b..484800ad7 100755
--- a/view/view-api-client/pom.xml
+++ b/view/view-api-client/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-view-api-client</artifactId>
diff --git a/view/view-api-client/src/main/kotlin/DataEntryQueryClient.kt b/view/view-api-client/src/main/kotlin/DataEntryQueryClient.kt
index 629ba9607..93ba397ec 100644
--- a/view/view-api-client/src/main/kotlin/DataEntryQueryClient.kt
+++ b/view/view-api-client/src/main/kotlin/DataEntryQueryClient.kt
@@ -11,7 +11,7 @@ import java.util.concurrent.CompletableFuture
 /**
  * Client encapsulating the correct query types (including response types)
  */
-class DataEntryQueryClient(
+open class DataEntryQueryClient(
   private val queryGateway: QueryGateway
 ) {
 
diff --git a/view/view-api-client/src/main/kotlin/ProcessDefinitionQueryClient.kt b/view/view-api-client/src/main/kotlin/ProcessDefinitionQueryClient.kt
index e2786b8ad..e0ae927e6 100644
--- a/view/view-api-client/src/main/kotlin/ProcessDefinitionQueryClient.kt
+++ b/view/view-api-client/src/main/kotlin/ProcessDefinitionQueryClient.kt
@@ -9,7 +9,7 @@ import java.util.concurrent.CompletableFuture
 /**
  * Client encapsulating the correct query types (including response types)
  */
-class ProcessDefinitionQueryClient(
+open class ProcessDefinitionQueryClient(
   private val queryGateway: QueryGateway
 ) {
 
diff --git a/view/view-api-client/src/main/kotlin/ProcessInstanceQueryClient.kt b/view/view-api-client/src/main/kotlin/ProcessInstanceQueryClient.kt
index b050aff15..315c50b4a 100644
--- a/view/view-api-client/src/main/kotlin/ProcessInstanceQueryClient.kt
+++ b/view/view-api-client/src/main/kotlin/ProcessInstanceQueryClient.kt
@@ -13,7 +13,7 @@ import java.util.concurrent.CompletableFuture
 /**
  * Client encapsulating the correct query types (including response types)
  */
-class ProcessInstanceQueryClient(
+open class ProcessInstanceQueryClient(
   private val queryGateway: QueryGateway
 ) {
 
diff --git a/view/view-api-client/src/main/kotlin/ProcessVariableQueryClient.kt b/view/view-api-client/src/main/kotlin/ProcessVariableQueryClient.kt
index c6b74497f..ae0bab539 100644
--- a/view/view-api-client/src/main/kotlin/ProcessVariableQueryClient.kt
+++ b/view/view-api-client/src/main/kotlin/ProcessVariableQueryClient.kt
@@ -15,7 +15,7 @@ import java.util.concurrent.CompletableFuture
 /**
  * Client encapsulating the correct query types (including response types)
  */
-class ProcessVariableQueryClient(
+open class ProcessVariableQueryClient(
   private val queryGateway: QueryGateway
 ) {
 
diff --git a/view/view-api-client/src/main/kotlin/QueryGatewayExt.kt b/view/view-api-client/src/main/kotlin/QueryGatewayExt.kt
index 4b9da2e1b..05c3e687f 100644
--- a/view/view-api-client/src/main/kotlin/QueryGatewayExt.kt
+++ b/view/view-api-client/src/main/kotlin/QueryGatewayExt.kt
@@ -128,4 +128,10 @@ object QueryGatewayExt {
    */
   fun QueryGateway.tasksWithDataEntriesForGroup(query: TasksWithDataEntriesForGroupQuery): CompletableFuture<TasksWithDataEntriesQueryResult> =
     TaskQueryClient(this).query(query)
+
+  /**
+   * @see [TasksForGroupQuery]
+   */
+  fun QueryGateway.tasksForCandidateUserAndGroup(query: TasksForCandidateUserAndGroupQuery): CompletableFuture<TaskQueryResult> = TaskQueryClient(this).query(query)
+
 }
diff --git a/view/view-api-client/src/main/kotlin/TaskQueryClient.kt b/view/view-api-client/src/main/kotlin/TaskQueryClient.kt
index 2f8e19129..8cd29dc4f 100644
--- a/view/view-api-client/src/main/kotlin/TaskQueryClient.kt
+++ b/view/view-api-client/src/main/kotlin/TaskQueryClient.kt
@@ -9,7 +9,7 @@ import java.util.concurrent.CompletableFuture
 /**
  * Client encapsulating the correct query types (including response types)
  */
-class TaskQueryClient(
+open class TaskQueryClient(
   private val queryGateway: QueryGateway
 ) {
 
@@ -17,7 +17,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksForUserQuery
    */
-  fun query(query: TasksForUserQuery): CompletableFuture<TaskQueryResult> =
+  open fun query(query: TasksForUserQuery): CompletableFuture<TaskQueryResult> =
     queryGateway.query(
       query,
       ResponseTypes.instanceOf(TaskQueryResult::class.java)
@@ -27,7 +27,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TaskForIdQuery
    */
-  fun query(query: TaskForIdQuery): CompletableFuture<Optional<Task>> = queryGateway.query(
+  open fun query(query: TaskForIdQuery): CompletableFuture<Optional<Task>> = queryGateway.query(
     query,
     ResponseTypes.optionalInstanceOf(Task::class.java)
   )
@@ -36,7 +36,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksForApplicationQuery
    */
-  fun query(query: TasksForApplicationQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
+  open fun query(query: TasksForApplicationQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TaskQueryResult::class.java)
   )
@@ -45,7 +45,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TaskWithDataEntriesForIdQuery
    */
-  fun query(query: TaskWithDataEntriesForIdQuery): CompletableFuture<Optional<TaskWithDataEntries>> = queryGateway.query(
+  open fun query(query: TaskWithDataEntriesForIdQuery): CompletableFuture<Optional<TaskWithDataEntries>> = queryGateway.query(
     query,
     ResponseTypes.optionalInstanceOf(TaskWithDataEntries::class.java)
   )
@@ -54,7 +54,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksWithDataEntriesForUserQuery
    */
-  fun query(query: TasksWithDataEntriesForUserQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
+  open fun query(query: TasksWithDataEntriesForUserQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TasksWithDataEntriesQueryResult::class.java)
   )
@@ -63,7 +63,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TaskCountByApplicationQuery
    */
-  fun query(query: TaskCountByApplicationQuery): CompletableFuture<List<ApplicationWithTaskCount>> = queryGateway.query(
+  open fun query(query: TaskCountByApplicationQuery): CompletableFuture<List<ApplicationWithTaskCount>> = queryGateway.query(
     query,
     ResponseTypes.multipleInstancesOf(ApplicationWithTaskCount::class.java)
   )
@@ -72,7 +72,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.AllTasksQuery
    */
-  fun query(query: AllTasksQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
+  open fun query(query: AllTasksQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TaskQueryResult::class.java)
   )
@@ -81,7 +81,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksWithDataEntriesQueryResult
    */
-  fun query(query: AllTasksWithDataEntriesQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
+  open fun query(query: AllTasksWithDataEntriesQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TasksWithDataEntriesQueryResult::class.java)
   )
@@ -90,7 +90,7 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksForGroupQuery
    */
-  fun query(query: TasksForGroupQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
+  open fun query(query: TasksForGroupQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TaskQueryResult::class.java)
   )
@@ -99,8 +99,18 @@ class TaskQueryClient(
    * @see io.holunda.polyflow.view.query.task.TaskApi.query
    * @see io.holunda.polyflow.view.query.task.TasksWithDataEntriesForGroupQuery
    */
-  fun query(query: TasksWithDataEntriesForGroupQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
+  open fun query(query: TasksWithDataEntriesForGroupQuery): CompletableFuture<TasksWithDataEntriesQueryResult> = queryGateway.query(
     query,
     ResponseTypes.instanceOf(TasksWithDataEntriesQueryResult::class.java)
   )
+
+  /**
+   * @see io.holunda.polyflow.view.query.task.TaskApi.query
+   * @see io.holunda.polyflow.view.query.task.TasksForCandidateUserAndGroupQuery
+   */
+  open fun query(query: TasksForCandidateUserAndGroupQuery): CompletableFuture<TaskQueryResult> = queryGateway.query(
+    query,
+    ResponseTypes.instanceOf(TaskQueryResult::class.java)
+  )
+
 }
diff --git a/view/view-api/pom.xml b/view/view-api/pom.xml
index fcafb5c90..bb94dfa00 100755
--- a/view/view-api/pom.xml
+++ b/view/view-api/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>io.holunda.polyflow</groupId>
     <artifactId>polyflow-view-parent</artifactId>
-    <version>3.10.1-SNAPSHOT</version>
+    <version>3.14.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>polyflow-view-api</artifactId>
diff --git a/view/view-api/src/main/kotlin/filter/Filter.kt b/view/view-api/src/main/kotlin/filter/Filter.kt
index eab6dd3e0..2d2cebe9a 100755
--- a/view/view-api/src/main/kotlin/filter/Filter.kt
+++ b/view/view-api/src/main/kotlin/filter/Filter.kt
@@ -248,7 +248,7 @@ internal fun toCriterion(filter: String): Criterion {
   }.map { it.trim() }
 
   // special handling for simple infix operators of form <field><op><value>
-  require(segments.size == 3 && segments[0].isNotBlank() && segments[0].isNotBlank()) { "Failed to create criteria from $filter." }
+  require(segments.size == 3 && segments[0].isNotBlank() && segments[1].isNotBlank()) { "Failed to create criteria from $filter." }
 
   return when {
     isTaskAttribute(segments[0]) -> {
diff --git a/view/view-api/src/main/kotlin/query/PageableSortableQuery.kt b/view/view-api/src/main/kotlin/query/PageableSortableQuery.kt
index f9f9dc340..13dc620b2 100644
--- a/view/view-api/src/main/kotlin/query/PageableSortableQuery.kt
+++ b/view/view-api/src/main/kotlin/query/PageableSortableQuery.kt
@@ -1,5 +1,10 @@
 package io.holunda.polyflow.view.query
 
+import io.holunda.polyflow.view.sort.SortDirection.ASCENDING
+import io.holunda.polyflow.view.sort.SortDirection.DESCENDING
+import kotlin.reflect.KClass
+import kotlin.reflect.full.declaredMemberProperties
+
 /**
  * Query interface for queries specifying the total amount of results, page and sort.
  */
@@ -7,4 +12,33 @@ interface PageableSortableQuery {
   val page: Int
   val size: Int
   val sort: String?
+
+  /**
+   * Checks that the sort parameter is correctly specified.
+   * @param clazz class containing member properties to be used as allowed fields.
+   */
+  fun <C : KClass<*>> sanitizeSort(clazz: C) {
+    sanitizeSort(clazz.declaredMemberProperties.map { it.name }.toSet())
+  }
+
+  /**
+   * Checks that the sort parameter is correctly specified.
+   */
+  fun sanitizeSort(fieldNames: Set<String>) {
+    if (sort == null) {
+      return
+    }
+    val direction = sort!!.substring(0, 1)
+    require(
+      direction == ASCENDING.sign
+        || direction == DESCENDING.sign
+    ) { "Sort must start either with '${ASCENDING.sign}' or '${DESCENDING.sign}' but it was starting with '$direction'" }
+    val parameter = sort!!.substring(1)
+    require(fieldNames.contains(parameter)) {
+      "Sort parameter must be one of ${
+        fieldNames.joinToString(", ")
+      } but it was $parameter."
+    }
+  }
+
 }
diff --git a/view/view-api/src/main/kotlin/query/QueryResult.kt b/view/view-api/src/main/kotlin/query/QueryResult.kt
index e8103dd31..d1d98a94c 100644
--- a/view/view-api/src/main/kotlin/query/QueryResult.kt
+++ b/view/view-api/src/main/kotlin/query/QueryResult.kt
@@ -2,6 +2,8 @@ package io.holunda.polyflow.view.query
 
 /**
  * Query result representing a list of elements and the total number of elements.
+ * @param [T] tpe of resulting element.
+ * @param [S] type of a concrete query (to be returned on query operations like slice).
  * @param elements elements in the query result.
  * @param totalElementCount in the result before the slice has been applied.
  */
@@ -13,7 +15,7 @@ open class QueryResult<T : Any, S : QueryResult<T, S>>(
 
   /**
    * Slices the result.
-   * @param query contaning slicing information.
+   * @param query containing slicing information.
    * @return result having the specified number of elements.
    */
   open fun slice(query: PageableSortableQuery): QueryResult<T, S> {
diff --git a/view/view-api/src/main/kotlin/query/task/TaskApi.kt b/view/view-api/src/main/kotlin/query/task/TaskApi.kt
index c880d9f77..3e6c88e64 100644
--- a/view/view-api/src/main/kotlin/query/task/TaskApi.kt
+++ b/view/view-api/src/main/kotlin/query/task/TaskApi.kt
@@ -29,7 +29,6 @@ interface TaskApi {
    */
   fun query(query: AllTasksWithDataEntriesQuery): TasksWithDataEntriesQueryResult
 
-
   /**
    * Count tasks and group by application.
    */
@@ -45,6 +44,11 @@ interface TaskApi {
    */
   fun query(query: TasksForGroupQuery): TaskQueryResult
 
+  /**
+   * Retrieves tasks for given user's groups and user's being candidates.
+   */
+  fun query(query: TasksForCandidateUserAndGroupQuery): TaskQueryResult
+
   /**
    * Retrieve task by given id.
    */
diff --git a/view/view-api/src/main/kotlin/query/task/TasksForCandidateUserAndGroupQuery.kt b/view/view-api/src/main/kotlin/query/task/TasksForCandidateUserAndGroupQuery.kt
new file mode 100755
index 000000000..f8983cc9d
--- /dev/null
+++ b/view/view-api/src/main/kotlin/query/task/TasksForCandidateUserAndGroupQuery.kt
@@ -0,0 +1,29 @@
+package io.holunda.polyflow.view.query.task
+
+import io.holunda.polyflow.view.Task
+import io.holunda.polyflow.view.auth.User
+
+/**
+ * Query for tasks visible for user.
+ * @param user - the user with groups accessing the tasks.
+ * @param includeAssigned flag indicating if assigned tasks are returned.
+ * @param page - page to read, zero-based index.
+ * @param size - size of the page
+ * @param sort - optional attribute to sort by.
+ * @param filters - the filters to further filter down the tasks.
+ */
+data class TasksForCandidateUserAndGroupQuery(
+  val user: User,
+  val includeAssigned: Boolean = true,
+  override val page: Int = 0,
+  override val size: Int = Int.MAX_VALUE,
+  override val sort: String? = null,
+  override val filters: List<String> = listOf()
+) : PageableSortableFilteredTaskQuery {
+
+  override fun applyFilter(element: Task): Boolean =
+    (element.candidateGroups.any { candidateGroup -> this.user.groups.contains(candidateGroup) }
+      || element.candidateUsers.contains(this.user.username)) && ((element.assignee != null) == includeAssigned)
+
+}
+
diff --git a/view/view-api/src/main/kotlin/query/task/TasksForUserQuery.kt b/view/view-api/src/main/kotlin/query/task/TasksForUserQuery.kt
index d05524524..5180445f7 100755
--- a/view/view-api/src/main/kotlin/query/task/TasksForUserQuery.kt
+++ b/view/view-api/src/main/kotlin/query/task/TasksForUserQuery.kt
@@ -2,12 +2,11 @@ package io.holunda.polyflow.view.query.task
 
 import io.holunda.polyflow.view.Task
 import io.holunda.polyflow.view.auth.User
-import io.holunda.polyflow.view.query.FilterQuery
-import io.holunda.polyflow.view.query.PageableSortableQuery
 
 /**
  * Query for tasks visible for user.
  * @param user - the user with groups accessing the tasks.
+ * @param assignedToMeOnly flag indicating if the resulting tasks must be assigned to the user only.
  * @param page - page to read, zero-based index.
  * @param size - size of the page
  * @param sort - optional attribute to sort by.
@@ -15,18 +14,37 @@ import io.holunda.polyflow.view.query.PageableSortableQuery
  */
 data class TasksForUserQuery(
   val user: User,
+  val assignedToMeOnly: Boolean = false,
   override val page: Int = 0,
   override val size: Int = Int.MAX_VALUE,
   override val sort: String? = null,
   override val filters: List<String> = listOf()
 ) : PageableSortableFilteredTaskQuery {
 
+  /**
+   * Compatibility constructor for old clients.
+   */
+  @Deprecated(message = "Please use other constructor setting the assignedToMeOnly.")
+  constructor(user: User, page: Int = 0, size: Int = Int.MAX_VALUE, sort: String? = null, filters: List<String> = listOf()): this(
+    user = user,
+    assignedToMeOnly = false,
+    page = page,
+    size = size,
+    sort = sort,
+    filters = filters
+  )
+
   override fun applyFilter(element: Task): Boolean =
-  // assignee
-    element.assignee == this.user.username
+    if (assignedToMeOnly) {
+      // assignee
+      element.assignee == this.user.username
+    } else {
       // candidate user
-      || (element.candidateUsers.contains(this.user.username))
-      // candidate groups
-      || (element.candidateGroups.any { candidateGroup -> this.user.groups.contains(candidateGroup) })
+      element.candidateUsers.contains(this.user.username)
+        // candidate groups
+        || element.candidateGroups.any { candidateGroup -> this.user.groups.contains(candidateGroup) }
+        // assignee
+        || element.assignee == this.user.username
+    }
 }
 
diff --git a/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForGroupQuery.kt b/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForGroupQuery.kt
index 81ea69e8f..e183a3f7e 100755
--- a/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForGroupQuery.kt
+++ b/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForGroupQuery.kt
@@ -1,6 +1,5 @@
 package io.holunda.polyflow.view.query.task
 
-import io.holunda.polyflow.view.Task
 import io.holunda.polyflow.view.TaskWithDataEntries
 import io.holunda.polyflow.view.auth.User
 import io.holunda.polyflow.view.query.FilterQuery
diff --git a/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForUserQuery.kt b/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForUserQuery.kt
index 191664431..33b975d36 100755
--- a/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForUserQuery.kt
+++ b/view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesForUserQuery.kt
@@ -8,6 +8,7 @@ import io.holunda.polyflow.view.query.PageableSortableQuery
 /**
  * Query for tasks with correlated data entries for given user.
  * @param user user able to see the tasks.
+ * @param assignedToMeOnly flag indicating if the resulting tasks must be assigned to the user only.
  * @param page current page, zero-based index.
  * @param size number of entries on every page.
  * @param sort property name of the {@link TaskWithDataEntries} to sort.
@@ -15,12 +16,28 @@ import io.holunda.polyflow.view.query.PageableSortableQuery
  */
 data class TasksWithDataEntriesForUserQuery(
   val user: User,
+  val assignedToMeOnly: Boolean = false,
   override val page: Int = 0,
   override val size: Int = Int.MAX_VALUE,
   override val sort: String? = null,
   val filters: List<String> = listOf()
 ) : FilterQuery<TaskWithDataEntries>, PageableSortableQuery {
 
+  /**
+   * Compatibility constructor for old clients.
+   */
+  @Deprecated("Please use other constructor setting the assignedToMeOnly.")
+  constructor(user: User, page: Int = 0, size: Int = Int.MAX_VALUE, sort: String? = null, filters: List<String> = listOf()) : this(
+    user = user, assignedToMeOnly = false, page = page, size = size, sort = sort, filters = filters
+  )
+
   override fun applyFilter(element: TaskWithDataEntries): Boolean =
-    TasksForUserQuery(user, page, size, sort, filters).applyFilter(element.task)
+    TasksForUserQuery(
+      user = user,
+      assignedToMeOnly = assignedToMeOnly,
+      page = page,
+      size = size,
+      sort = sort,
+      filters = filters
+    ).applyFilter(element.task)
 }


Test patch:
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/collector/properties/CamundaTaskpoolCollectorPropertiesExtendedTest.kt b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/collector/properties/CamundaTaskpoolCollectorPropertiesExtendedTest.kt
index 458d2bd46..d0f1ba439 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/collector/properties/CamundaTaskpoolCollectorPropertiesExtendedTest.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/collector/properties/CamundaTaskpoolCollectorPropertiesExtendedTest.kt
@@ -83,6 +83,31 @@ internal class CamundaTaskpoolCollectorPropertiesExtendedTest {
       }
   }
 
+  @Test
+  fun `loads properties configuration to ignore listeners`() {
+    contextRunner
+      .withUserConfiguration(TestMockConfiguration::class.java)
+      .withUserConfiguration(AdditionalMockConfiguration::class.java)
+      .withPropertyValues(
+        "spring.application.name=my-test-application",
+        "camunda.bpm.eventing.task=false",
+        "polyflow.integration.collector.camunda.task.enabled=true",
+        "polyflow.integration.collector.camunda.task.enricher.type=custom",
+        "polyflow.integration.collector.camunda.task.excluded-task-event-names=assignment",
+        "polyflow.integration.collector.camunda.task.excluded-history-event-names=add-identity-link,delete-identity-link",
+      ).run {
+
+        assertThat(it.getBean(CamundaTaskpoolCollectorProperties::class.java)).isNotNull
+        val props: CamundaTaskpoolCollectorProperties = it.getBean(CamundaTaskpoolCollectorProperties::class.java)
+
+        assertThat(props.task.enabled).isTrue
+        assertThat(props.task.collectTaskEvent("assignment")).isFalse()
+        assertThat(props.task.collectHistoryEvent("add-identity-link")).isFalse()
+        assertThat(props.task.collectHistoryEvent("delete-identity-link")).isFalse()
+      }
+  }
+
+
   /**
    * Config class without configuration annotation not to confuse others.
    */
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/TestDriver.kt b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/TestDriver.kt
index e6f6e4870..7b35e6ff1 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/TestDriver.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/TestDriver.kt
@@ -145,8 +145,8 @@ class TestDriver(
 
   }
 
-  fun assertProcessInstanceWaitsInUserTask(instance: ProcessInstance) {
-    BpmnAwareTests.assertThat(instance).isWaitingAt(TASK_DEFINITION_KEY)
+  fun assertProcessInstanceWaitsInUserTask(instance: ProcessInstance, taskDefinitionKey: String = TASK_DEFINITION_KEY) {
+    BpmnAwareTests.assertThat(instance).isWaitingAt(taskDefinitionKey)
   }
 
   /*
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/ProcessDefinitionServiceITest.kt b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/ProcessDefinitionServiceITest.kt
index 125771b68..f5914dfe8 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/ProcessDefinitionServiceITest.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/ProcessDefinitionServiceITest.kt
@@ -86,6 +86,52 @@ class ProcessDefinitionServiceITest {
     assertThat(definitions[0].candidateStarterGroups).containsExactlyElementsOf(listOf("muppetshow"))
   }
 
+  @Test
+  fun `should not deliver process starter if no start form is available`() {
+
+    val processId = "my-id"
+    val startEventId = "start"
+    val modelInstance = Bpmn
+      .createExecutableProcess(processId)
+      .startEvent(startEventId)
+      .endEvent("end")
+      .done().apply {
+        getModelElementById<ModelElementInstance>(processId).setAttributeValue("name", "My Process")
+        getModelElementById<ModelElementInstance>(processId).setAttributeValueNs(NS_CAMUNDA, "candidateStarterGroups", "muppetshow")
+      }
+
+    repositoryService
+      .createDeployment()
+      .addModelInstance("process-without-start-form.bpmn", modelInstance)
+      .deploy()
+
+
+    val definitions = processDefinitionService.getProcessDefinitions(processEngine.processEngineConfiguration as ProcessEngineConfigurationImpl)
+
+    assertThat(definitions).isNotEmpty
+    assertThat(definitions[0].processName).isEqualTo("My Process")
+    assertThat(definitions[0].processDefinitionKey).isEqualTo("my-id")
+    assertThat(definitions[0].processDefinitionVersion).isEqualTo(1)
+    assertThat(definitions[0].formKey).isNull()
+    assertThat(definitions[0].candidateStarterGroups).containsExactlyElementsOf(listOf("muppetshow"))
+  }
+
+  @Test
+  fun `should not deliver process starter if only two message start events are available`() {
+    repositoryService
+      .createDeployment()
+      .addClasspathResource("itest/message_start_event.bpmn")
+      .deploy()
+
+    val definitions = processDefinitionService.getProcessDefinitions(processEngine.processEngineConfiguration as ProcessEngineConfigurationImpl)
+
+    assertThat(definitions).isNotEmpty
+    assertThat(definitions[0].processName).isEqualTo("My Process")
+    assertThat(definitions[0].processDefinitionKey).isEqualTo("my-id")
+    assertThat(definitions[0].processDefinitionVersion).isEqualTo(1)
+    assertThat(definitions[0].formKey).isNull()
+  }
+
   /**
    * Internal test application.
    */
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/TaskCollectorITest.kt b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/TaskCollectorITest.kt
index 92dbec1d0..963bf20f6 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/TaskCollectorITest.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/tx/TaskCollectorITest.kt
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.module.kotlin.convertValue
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import io.holunda.camunda.taskpool.api.task.*
 import io.holunda.polyflow.taskpool.EnableCamundaTaskpoolCollector
+import io.holunda.polyflow.taskpool.collector.task.TaskEventCollectorService
 import io.holunda.polyflow.taskpool.itest.TestDriver
 import io.holunda.polyflow.taskpool.itest.TestDriver.Companion.DEFAULT_VARIABLES
 import io.holunda.polyflow.taskpool.itest.TestDriver.Companion.createTaskCommand
@@ -17,6 +18,7 @@ import org.axonframework.commandhandling.gateway.CommandGateway
 import org.camunda.bpm.engine.RepositoryService
 import org.camunda.bpm.engine.RuntimeService
 import org.camunda.bpm.engine.TaskService
+import org.camunda.bpm.engine.delegate.DelegateTask
 import org.camunda.bpm.engine.delegate.TaskListener
 import org.camunda.bpm.engine.impl.interceptor.Command
 import org.camunda.bpm.engine.impl.interceptor.CommandExecutor
@@ -32,6 +34,8 @@ import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.boot.test.mock.mockito.MockBean
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Primary
+import org.springframework.context.event.EventListener
+import org.springframework.core.annotation.Order
 import org.springframework.test.annotation.DirtiesContext
 import org.springframework.test.context.ActiveProfiles
 import java.time.Instant.now
@@ -647,6 +651,43 @@ internal class TaskCollectorITest {
 
   }
 
+  /**
+   * The process is started and waits in a user task. The user task has a task listener that changes some local process variables on create.
+   * The create command should contain the local variables.
+   */
+  @Test
+  fun `updates variables with create listener implemented as spring event handler`() {
+
+    // deploy
+    driver.deployProcess(
+      createUserTaskProcess(
+        taskDefinitionKey = "eventing",
+        taskListeners = listOf(
+          "create" to "#{setTaskLocalVariables}" // this one will be ignored, since it is invoked after enrichment
+        )
+      )
+    )
+
+
+    // start
+    val instance = driver.startProcessInstance(variables = Variables.createVariables().putValue("overriddenVariable", "global-value"))
+    driver.assertProcessInstanceWaitsInUserTask(instance, "eventing")
+
+    val createCommand = createTaskCommand(
+      variables = Variables.createVariables()
+        .putValue("taskLocalOnlyVariable", "only-value-by-event-handler")
+        .putValue("overriddenVariable", "local-value-by-event-handler")
+    )
+
+
+    waitAtMost(3, TimeUnit.SECONDS).untilAsserted {
+      verify(commandListGateway).sendToGateway(
+        listOf(createCommand)
+      )
+    }
+
+    verifyNoMoreInteractions(commandListGateway)
+  }
 
   /**
    * Internal test application.
@@ -694,6 +735,26 @@ internal class TaskCollectorITest {
       delegateTask.dueDate = TestDriver.NOW
       delegateTask.followUpDate = TestDriver.NOW
     }
+
+    /**
+     * A task listener that sets some local variables.
+     */
+    @Order(TaskEventCollectorService.ORDER - 80)
+    @EventListener(condition = "#delegateTask.taskDefinitionKey.equals('eventing') && #delegateTask.eventName.equals('create')")
+    fun setTaskLocalVariables(delegateTask: DelegateTask) {
+      delegateTask.setVariableLocal("taskLocalOnlyVariable", "only-value-by-event-handler")
+      delegateTask.setVariableLocal("overriddenVariable", "local-value-by-event-handler")
+    }
+
+
+    /**
+     * A task listener that sets some local variables.
+     */
+    @Bean
+    fun setTaskLocalVariables() = TaskListener { delegateTask ->
+      delegateTask.setVariableLocal("taskLocalOnlyVariable", "only-value")
+      delegateTask.setVariableLocal("overriddenVariable", "local-value")
+    }
   }
 
 }
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/txjob/TaskTxJobSenderITest.kt b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/txjob/TaskTxJobSenderITest.kt
index bd5b4d011..eeddff42d 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/txjob/TaskTxJobSenderITest.kt
+++ b/integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/txjob/TaskTxJobSenderITest.kt
@@ -7,17 +7,16 @@ import io.holunda.polyflow.taskpool.itest.TestDriver
 import io.holunda.polyflow.taskpool.itest.TestDriver.Companion.createUserTaskProcess
 import io.holunda.polyflow.taskpool.sender.gateway.CommandListGateway
 import org.assertj.core.api.Assertions
+import org.awaitility.Awaitility
 import org.axonframework.commandhandling.gateway.CommandGateway
 import org.camunda.bpm.engine.ManagementService
 import org.camunda.bpm.engine.RepositoryService
 import org.camunda.bpm.engine.RuntimeService
-import org.camunda.bpm.engine.TaskService
-import org.camunda.bpm.engine.impl.interceptor.Command
-import org.camunda.bpm.engine.impl.interceptor.CommandExecutor
+import org.camunda.bpm.engine.delegate.TaskListener
+import org.camunda.bpm.engine.impl.persistence.entity.MessageEntity
 import org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*
+import org.camunda.bpm.engine.variable.Variables
 import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication
-import org.junit.After
-import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.Test
@@ -30,20 +29,20 @@ import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.boot.test.mock.mockito.MockBean
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Primary
-import org.springframework.test.annotation.Commit
 import org.springframework.test.annotation.DirtiesContext
-import org.springframework.test.annotation.Rollback
 import org.springframework.test.context.ActiveProfiles
-import org.springframework.test.context.transaction.AfterTransaction
+import org.springframework.transaction.annotation.Propagation
 import org.springframework.transaction.annotation.Transactional
-import org.springframework.transaction.support.TransactionSynchronization
+import org.springframework.transaction.support.TransactionTemplate
 import java.util.*
+import java.util.concurrent.TimeUnit
 
 
-@Disabled("Understand how to test this")
 @SpringBootTest(classes = [TaskTxJobSenderITest.TaskTxJobSenderTestApplication::class], webEnvironment = SpringBootTest.WebEnvironment.MOCK)
 @ActiveProfiles("txjob-sender-itest")
 @DirtiesContext
+@Transactional
+@Disabled("This test sometimes fails because it can't create a new TX (Entity Manager is closed).")
 internal class TaskTxJobSenderITest {
 
   @MockBean
@@ -59,63 +58,111 @@ internal class TaskTxJobSenderITest {
   lateinit var managementService: ManagementService
 
   @Autowired
-  lateinit var taskServiceService: TaskService
-
-
-  @Autowired
-  lateinit var commandExecutor: CommandExecutor
+  lateinit var txTemplate: TransactionTemplate
 
+  lateinit var createCommand: CreateTaskCommand
 
   private val driver: TestDriver by lazy {
     TestDriver(repositoryService, runtimeService)
   }
 
-
   @BeforeEach
-  fun `start process and create user task`() {
-
+  fun `setup tx template`() {
+    txTemplate.propagationBehavior = Propagation.REQUIRES_NEW.value()
   }
 
   @Test
-  @Transactional
-  @Commit
   fun `creates task in process`() {
-    // deploy
-    driver.deployProcess(
-      createUserTaskProcess()
-    )
 
-//    commandExecutor.execute {
-//      Command {
-        // start
-        val instance = driver.startProcessInstance()
-        // instance is started
-        assertThat(instance).isStarted
-        // user task
-        driver.assertProcessInstanceWaitsInUserTask(instance)
-//      }
-//    }
+    doInTransaction {
+      // deploy
+      driver.deployProcess(
+        createUserTaskProcess()
+      )
 
+      // start
+      val instance = driver.startProcessInstance()
+      // instance is started
+      assertThat(instance).isStarted
+      // user task
+      driver.assertProcessInstanceWaitsInUserTask(instance)
 
-    /*
+      verifyNoMoreInteractions(commandListGateway)
+
+      createCommand = TestDriver.createTaskCommand()
+    }
+
+    assertAndExecuteCommandSendingJob()
+
+    verify(commandListGateway).sendToGateway(
+      listOf(createCommand)
+    )
+  }
 
-        val createCommand = createTaskCommand(
-          candidateUsers = setOf("piggy"),
-          candidateGroups = setOf("muppetshow"),
+  /**
+   * The process is started and waits in a user task. The user task has a task listener that changes some local process variables on create.
+   * The create command should contain the local variables.
+   */
+  @Test
+  @Disabled("Find out why the local listener update always gt into the next TX and how to deal with it")
+  fun `updates variables with create listener`() {
+
+    doInTransaction {
+      // deploy
+      driver.deployProcess(
+        createUserTaskProcess(
+          taskListeners = listOf(
+            "create" to "#{setTaskLocalVariables}"
+          )
         )
-    */
+      )
+
+      // start
+      val instance = driver.startProcessInstance(variables = Variables.createVariables().putValue("overriddenVariable", "global-value"))
+      driver.assertProcessInstanceWaitsInUserTask(instance)
+
+      verifyNoMoreInteractions(commandListGateway)
 
+      createCommand = TestDriver.createTaskCommand(
+        variables = Variables.createVariables()
+          .putValue("taskLocalOnlyVariable", "only-value")
+          .putValue("overriddenVariable", "local-value")
+      )
+    }
 
-    verifyNoMoreInteractions(commandListGateway)
+    assertAndExecuteCommandSendingJob()
+
+    verify(commandListGateway).sendToGateway(
+      listOf(createCommand)
+    )
 
   }
 
-  @AfterTransaction
-  fun `after all`() {
-    val jobs = managementService.createJobQuery().list()
-    Assertions.assertThat(jobs).hasSize(1)
+  private fun assertAndExecuteCommandSendingJob() {
+    doInTransaction {
+      val jobs = managementService.createJobQuery().list()
+      Assertions.assertThat(jobs).hasSize(1)
+      Assertions.assertThat(jobs[0]).isInstanceOf(MessageEntity::class.java)
+      Assertions.assertThat((jobs[0] as MessageEntity).jobHandlerType).isEqualTo("polyflow-engine-task-command-sending")
+
+      Awaitility.waitAtMost(3, TimeUnit.SECONDS).untilAsserted {
+        try {
+          execute(jobs[0])
+        } catch (e: Exception) {
+          // brute force preventing Optimistic locking exception, IllegalStateException (job doesn't exist)
+        }
+        Assertions.assertThat(managementService.createJobQuery().count()).isEqualTo(0)
+      }
+    }
   }
 
+  private fun doInTransaction(operation: Runnable) {
+    txTemplate.execute<Any> {
+      operation.run()
+      null
+    }
+
+  }
 
   @SpringBootApplication
   @EnableProcessApplication
@@ -126,5 +173,15 @@ internal class TaskTxJobSenderITest {
     @Bean
     @Primary
     fun testTxJobAxonCommandGateway(): CommandGateway = mock()
+
+    /**
+     * A task listener that sets some local variables.
+     */
+    @Bean
+    fun setTaskLocalVariables() = TaskListener { delegateTask ->
+      delegateTask.setVariableLocal("taskLocalOnlyVariable", "only-value")
+      delegateTask.setVariableLocal("overriddenVariable", "local-value")
+    }
+
   }
 }
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/resources/application-txjob-sender-itest.yml b/integration/camunda-bpm/taskpool-collector/src/test/resources/application-txjob-sender-itest.yml
index 6c3a453c9..2b0e97a03 100644
--- a/integration/camunda-bpm/taskpool-collector/src/test/resources/application-txjob-sender-itest.yml
+++ b/integration/camunda-bpm/taskpool-collector/src/test/resources/application-txjob-sender-itest.yml
@@ -1,5 +1,5 @@
 spring:
-  application.name: txjob-sender-test
+  application.name: collector-test
   jpa:
     open-in-view: true # disable JPA warning
     show-sql: true
@@ -17,7 +17,16 @@ camunda:
 
 polyflow:
   integration:
+    collector:
+      camunda:
+        task:
+          enabled: true
+        process-instance:
+          enabled: false
+        process-definition:
+          enabled: false
     sender:
       task:
         type: txjob
         send-within-transaction: true
+
diff --git a/integration/camunda-bpm/taskpool-collector/src/test/resources/itest/message_start_event.bpmn b/integration/camunda-bpm/taskpool-collector/src/test/resources/itest/message_start_event.bpmn
new file mode 100644
index 000000000..67f5ead53
--- /dev/null
+++ b/integration/camunda-bpm/taskpool-collector/src/test/resources/itest/message_start_event.bpmn
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0xgy7na" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.10.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.19.0">
+  <bpmn:process id="my-id" name="My Process" isExecutable="true" camunda:historyTimeToLive="0">
+    <bpmn:endEvent id="Event_0b6e9a9">
+      <bpmn:incoming>Flow_0rqm55e</bpmn:incoming>
+      <bpmn:incoming>Flow_1k4xpiz</bpmn:incoming>
+    </bpmn:endEvent>
+    <bpmn:sequenceFlow id="Flow_0rqm55e" sourceRef="StartEvent_1" targetRef="Event_0b6e9a9" />
+    <bpmn:sequenceFlow id="Flow_1k4xpiz" sourceRef="Event_0tam437" targetRef="Event_0b6e9a9" />
+    <bpmn:startEvent id="StartEvent_1">
+      <bpmn:outgoing>Flow_0rqm55e</bpmn:outgoing>
+      <bpmn:messageEventDefinition id="MessageEventDefinition_1nlj1v7" messageRef="Message_2t2ssos" />
+    </bpmn:startEvent>
+    <bpmn:startEvent id="Event_0tam437">
+      <bpmn:outgoing>Flow_1k4xpiz</bpmn:outgoing>
+      <bpmn:messageEventDefinition id="MessageEventDefinition_1ft2zip" messageRef="Message_22tfs8s" />
+    </bpmn:startEvent>
+  </bpmn:process>
+  <bpmn:message id="Message_2t2ssos" name="start_message" />
+  <bpmn:message id="Message_22tfs8s" name="another_message" />
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="my-id">
+      <bpmndi:BPMNShape id="Event_0b6e9a9_di" bpmnElement="Event_0b6e9a9">
+        <dc:Bounds x="272" y="79" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_0qcrckj_di" bpmnElement="StartEvent_1">
+        <dc:Bounds x="179" y="79" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_02sa6i2_di" bpmnElement="Event_0tam437">
+        <dc:Bounds x="179" y="152" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_0rqm55e_di" bpmnElement="Flow_0rqm55e">
+        <di:waypoint x="215" y="97" />
+        <di:waypoint x="272" y="97" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1k4xpiz_di" bpmnElement="Flow_1k4xpiz">
+        <di:waypoint x="215" y="170" />
+        <di:waypoint x="244" y="170" />
+        <di:waypoint x="244" y="97" />
+        <di:waypoint x="272" y="97" />
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceDataEntryITest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceDataEntryITest.kt
index 622ed6d4c..525c80690 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceDataEntryITest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceDataEntryITest.kt
@@ -29,6 +29,7 @@ import org.mockito.kotlin.clearInvocations
 import org.mockito.kotlin.verify
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.annotation.DirtiesContext
 import org.springframework.test.context.ActiveProfiles
 import org.springframework.test.context.junit.jupiter.SpringExtension
 import org.springframework.transaction.annotation.Transactional
@@ -47,6 +48,7 @@ import java.util.function.Predicate
 )
 @ActiveProfiles("itest", "mock-query-emitter")
 @Transactional
+@DirtiesContext
 internal class JpaPolyflowViewServiceDataEntryITest {
 
   private val emittedQueryUpdates: MutableList<QueryUpdate<Any>> = mutableListOf()
@@ -263,7 +265,7 @@ internal class JpaPolyflowViewServiceDataEntryITest {
   fun `should find the entry by filter`() {
     assertResultIsTestEntry1And2(
       jpaPolyflowViewService.query(
-        DataEntriesQuery(filters = listOf("key=value"))
+        DataEntriesQuery(filters = listOf("key=value", "key=value2", "key=value3"))
       )
     )
   }
@@ -306,8 +308,9 @@ internal class JpaPolyflowViewServiceDataEntryITest {
 
   private fun assertResultIsTestEntry1And2(result: QueryResponseMessage<DataEntriesQueryResult>) {
     assertThat(result.payload.elements.size).isEqualTo(2)
-    assertTestDataEntry1(result.payload.elements[0])
-    assertTestDataEntry2(result.payload.elements[1])
+    assertThat(result.payload.elements.map { it.entryId }).containsExactlyInAnyOrder(id, id2)
+    assertTestDataEntry1(result.payload.elements.first { it.entryId == id })
+    assertTestDataEntry2(result.payload.elements.first { it.entryId == id2 })
   }
 
 
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceTaskITest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceTaskITest.kt
index 0d05f03b3..52f4acaea 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceTaskITest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/JpaPolyflowViewServiceTaskITest.kt
@@ -12,6 +12,7 @@ import io.holunda.polyflow.view.TaskWithDataEntries
 import io.holunda.polyflow.view.auth.User
 import io.holunda.polyflow.view.jpa.itest.TestApplication
 import io.holunda.polyflow.view.jpa.process.toSourceReference
+import io.holunda.polyflow.view.query.data.DataEntriesForUserQuery
 import io.holunda.polyflow.view.query.task.*
 import org.assertj.core.api.Assertions.assertThat
 import org.axonframework.messaging.MetaData
@@ -22,7 +23,7 @@ import org.camunda.bpm.engine.variable.Variables.createVariables
 import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.assertThrows
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.atLeast
 import org.mockito.kotlin.clearInvocations
@@ -30,7 +31,6 @@ import org.mockito.kotlin.verify
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.test.context.ActiveProfiles
-import org.springframework.test.context.junit.jupiter.SpringExtension
 import org.springframework.transaction.annotation.Transactional
 import java.time.Instant
 import java.time.OffsetDateTime
@@ -77,15 +77,6 @@ internal class JpaPolyflowViewServiceTaskITest {
 
   @BeforeEach
   fun `ingest events`() {
-    val payload = mapOf(
-      "key" to "value",
-      "key-int" to 1,
-      "complex" to Pojo(
-        attribute1 = "value",
-        attribute2 = Date.from(now)
-      )
-    )
-
     jpaPolyflowViewService.on(
       event = TaskCreatedEngineEvent(
         id = id,
@@ -93,7 +84,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 1",
         priority = 50,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload()) },
         businessKey = "business-1",
         createTime = Date.from(now),
         candidateUsers = setOf("kermit"),
@@ -108,7 +99,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 1",
         priority = 25,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload()) },
         businessKey = "business-1",
         createTime = Date.from(now),
         candidateUsers = setOf("kermit"),
@@ -124,7 +115,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 2",
         priority = 10,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload()) },
         businessKey = "business-2",
         createTime = Date.from(now),
         candidateUsers = setOf("piggy"),
@@ -139,7 +130,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 2",
         priority = 10,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload()) },
         businessKey = "business-2",
         createTime = Date.from(now),
         assignee = "piggy",
@@ -156,7 +147,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 3",
         priority = 10,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload()) },
         correlations = newCorrelations().apply { put(dataType1, dataId1) },
         businessKey = "business-3",
         createTime = Date.from(now),
@@ -173,7 +164,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         applicationName = "test-application",
         name = "Test Entry 1",
         state = ProcessingType.IN_PROGRESS.of("In progress"),
-        payload = serialize(payload = payload, mapper = objectMapper),
+        payload = serialize(payload = createPayload("dataEntry1"), mapper = objectMapper),
         authorizations = listOf(
           AuthorizationChange.addUser("luffy"),
           AuthorizationChange.addGroup("strawhats")
@@ -196,7 +187,7 @@ internal class JpaPolyflowViewServiceTaskITest {
         name = "task name 4",
         priority = 10,
         sourceReference = processReference().toSourceReference(),
-        payload = createVariables().apply { putAll(payload) },
+        payload = createVariables().apply { putAll(createPayload("otherValue")) },
         correlations = newCorrelations().apply {
           put(dataType1, dataId1)
           put(dataType2, dataId2)
@@ -215,9 +206,9 @@ internal class JpaPolyflowViewServiceTaskITest {
         entryId = dataId2,
         type = "Test",
         applicationName = "test-application",
-        name = "Test Entry 1",
+        name = "Test Entry 2",
         state = ProcessingType.IN_PROGRESS.of("In progress"),
-        payload = serialize(payload = payload, mapper = objectMapper),
+        payload = serialize(payload = createPayload("dataEntry2"), mapper = objectMapper),
         authorizations = listOf(
           AuthorizationChange.addUser("zoro")
         ),
@@ -258,14 +249,14 @@ internal class JpaPolyflowViewServiceTaskITest {
 
   @Test
   fun `should find the task by user with data entries`() {
-    val zoro = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(user = User("zoro", setOf())))
+    val zoro = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(user = User("zoro", setOf()), assignedToMeOnly = false))
     assertThat(zoro.elements).isNotEmpty.hasSize(1)
     assertThat(zoro.elements[0].task.id).isEqualTo(id4)
     assertThat(zoro.elements[0].task.name).isEqualTo("task name 4")
     assertThat(zoro.elements[0].dataEntries).isNotEmpty.hasSize(1)
     assertThat(zoro.elements[0].dataEntries[0].entryId).isEqualTo(dataId2)
 
-    val strawhats = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(user = User("other", setOf("strawhats"))))
+    val strawhats = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(user = User("other", setOf("strawhats")), assignedToMeOnly = false))
     assertThat(strawhats.elements).isNotEmpty.hasSize(2)
     assertThat(strawhats.elements.map { it.task.id }).contains(id3, id4)
     assertThat(strawhats.elements[0].dataEntries).hasSize(1)
@@ -274,6 +265,54 @@ internal class JpaPolyflowViewServiceTaskITest {
     assertThat(strawhats.elements[1].dataEntries[0].entryId).isEqualTo(dataId1)
   }
 
+  @Test
+  fun `should find the task by user with data entries and sort results correctly`() {
+    val strawhats = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(
+      user = User("other", setOf("strawhats")),
+      sort = "+name",
+      assignedToMeOnly = false
+    ))
+    val strawhatsInverse = jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(
+      user = User("other", setOf("strawhats")),
+      sort = "-name",
+      assignedToMeOnly = false
+    ))
+
+    assertThat(strawhats.elements).isNotEmpty.hasSize(2)
+    assertThat(strawhats.elements.map { it.task.id }).containsExactly(id3, id4)
+    assertThat(strawhatsInverse.elements).isNotEmpty.hasSize(2)
+    assertThat(strawhatsInverse.elements.map { it.task.id }).containsExactly(id4, id3)
+  }
+
+  @Test
+  fun `should not execute query because of wrong sort`() {
+    val user = User("other", setOf("strawhats"))
+    assertThat(assertThrows<IllegalArgumentException> {
+      jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(
+        user = user,
+        sort = "+createdTime", // entity property
+        assignedToMeOnly = false
+      ))
+    }.message).startsWith("Sort parameter must be one of ").endsWith(" but it was createdTime.")
+
+    assertThat(assertThrows<IllegalArgumentException> {
+      jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(
+        user = user,
+        sort = "+candidateUsers", // unsupported by JPA view
+        assignedToMeOnly = false
+      ))
+    }.message).isEqualTo("'candidateUsers' is not supported for sorting in JPA View")
+
+    assertThat(assertThrows<IllegalArgumentException> {
+      jpaPolyflowViewService.query(TasksWithDataEntriesForUserQuery(
+        user = user,
+        sort = "*name", // wrong order
+        assignedToMeOnly = false
+      ))
+    }.message).isEqualTo("Sort must start either with '+' or '-' but it was starting with '*'")
+
+  }
+
   @Test
   fun `should find the task by group with data entries`() {
     val strawhats = jpaPolyflowViewService.query(TasksWithDataEntriesForGroupQuery(user = User("some", setOf("strawhats")), includeAssigned = false))
@@ -294,15 +333,76 @@ internal class JpaPolyflowViewServiceTaskITest {
 
   @Test
   fun `should find the task by user`() {
-    val kermit = jpaPolyflowViewService.query(TasksForUserQuery(user = User("kermit", setOf())))
+    val kermit = jpaPolyflowViewService.query(TasksForUserQuery(user = User("kermit", setOf()), assignedToMeOnly = false))
     assertThat(kermit.elements).isNotEmpty
     assertThat(kermit.elements[0].id).isEqualTo(id)
     assertThat(kermit.elements[0].name).isEqualTo("task name 1")
-    val muppets = jpaPolyflowViewService.query(TasksForUserQuery(user = User("other", setOf("muppets"))))
+    val muppets = jpaPolyflowViewService.query(TasksForUserQuery(user = User("other", setOf("muppets")), assignedToMeOnly = false))
     assertThat(muppets.elements).isNotEmpty
     assertThat(muppets.elements[0].id).isEqualTo(id)
   }
 
+  @Test
+  fun `should find the task by user assigned to me`() {
+    val luffy = jpaPolyflowViewService.query(TasksForUserQuery(user = User("luffy", setOf()), assignedToMeOnly = false))
+    assertThat(luffy.elements).isNotEmpty
+    assertThat(luffy.elements[0].id).isEqualTo(id3)
+    assertThat(luffy.elements[0].name).isEqualTo("task name 3")
+
+    val zoro = jpaPolyflowViewService.query(TasksForUserQuery(user = User("zoro", setOf()), assignedToMeOnly = true))
+    assertThat(zoro.elements).isNotEmpty
+    assertThat(zoro.elements[0].id).isEqualTo(id4)
+    assertThat(zoro.elements[0].name).isEqualTo("task name 4")
+
+  }
+
+  @Test
+  fun `should or-compose task payload filters on same attribute`() {
+    val query = jpaPolyflowViewService.query(
+      TasksForUserQuery(
+        user = User("zoro", setOf("strawhats")),
+        assignedToMeOnly = false,
+        filters = listOf("key=value", "key=otherValue", "key=anotherValue")
+      )
+    )
+    assertThat(query.elements).hasSize(2)
+  }
+
+  @Test
+  fun `should or-compose data entry payload filters on same attribute`() {
+    val query = jpaPolyflowViewDataEntryService.query(
+      DataEntriesForUserQuery(
+        user = User("zoro", setOf("strawhats")),
+        filters = listOf("key=dataEntry1", "key=dataEntry2", "key=dataEntryFoo")
+      )
+    )
+    assertThat(query.payload.elements).hasSize(2)
+  }
+
+  @Test
+  fun `should or-compose task attribute filters on same attribute`() {
+    val kermit = jpaPolyflowViewService.query(
+      TasksForUserQuery(
+        user = User("zoro", setOf("strawhats")),
+        assignedToMeOnly = false,
+        filters = listOf("task.businessKey=business-3", "task.businessKey=business-4")
+      )
+    )
+    assertThat(kermit.elements).hasSize(2)
+  }
+
+  @Test
+  fun `should or-compose date entry attribute filters on same attribute`() {
+    val kermit = jpaPolyflowViewService.query(
+      TasksWithDataEntriesForUserQuery(
+        user = User("zoro", setOf("strawhats")),
+        assignedToMeOnly = false,
+        filters = listOf("data.entryId=${dataId1}", "data.entryId=${dataId2}")
+      )
+    )
+    assertThat(kermit.elements).hasSize(2)
+  }
+
   @Test
   fun `should find the task by group`() {
     val unassigned = jpaPolyflowViewService.query(TasksForGroupQuery(user = User("other", setOf("muppets")), includeAssigned = false))
@@ -314,6 +414,19 @@ internal class JpaPolyflowViewServiceTaskITest {
     assertThat(assigned.elements[0].name).isEqualTo("task name 1")
   }
 
+  @Test
+  fun `should find the task by candidate user and group`() {
+    val unassigned = jpaPolyflowViewService.query(TasksForCandidateUserAndGroupQuery(user = User("zoro", setOf("muppets")), includeAssigned = false))
+    assertThat(unassigned.elements).isEmpty()
+
+    val assigned = jpaPolyflowViewService.query(TasksForCandidateUserAndGroupQuery(user = User("zoro", setOf("muppets")), includeAssigned = true))
+    assertThat(assigned.elements).hasSize(2)
+    assertThat(assigned.elements[0].id).isEqualTo(id)
+    assertThat(assigned.elements[0].name).isEqualTo("task name 1")
+    assertThat(assigned.elements[1].id).isEqualTo(id4)
+    assertThat(assigned.elements[1].name).isEqualTo("task name 4")
+  }
+
 
   @Test
   fun `query updates are sent`() {
@@ -386,4 +499,14 @@ internal class JpaPolyflowViewServiceTaskITest {
 
   }
 
+  private fun createPayload(value: String = "value"): Map<String, Any> {
+    return mapOf(
+      "key" to value,
+      "key-int" to 1,
+      "complex" to Pojo(
+        attribute1 = "value",
+        attribute2 = Date.from(now)
+      )
+    )
+  }
 }
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/SpecificationTest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/SpecificationTest.kt
index 5c33a2ec1..bb81e5bf9 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/SpecificationTest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/SpecificationTest.kt
@@ -6,6 +6,9 @@ import io.holunda.polyflow.view.jpa.auth.AuthorizationPrincipal.Companion.user
 import io.holunda.polyflow.view.jpa.data.DataEntryRepository
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import org.springframework.data.domain.Sort.Direction
+import java.lang.NumberFormatException
 
 /**
  * Tests conversion of criteria into JPA Specifications.
@@ -36,6 +39,46 @@ internal class SpecificationTest {
     assertThat(specification).isNotNull
   }
 
+  @Test
+  fun `creates multiple attribute specification for tasks`() {
+    val filters = listOf(
+      "task.priority=50",
+      "task.businessKey=business-1"
+    )
+    val criteria = toCriteria(filters)
+
+    val specification = criteria.toTaskSpecification()
+    assertThat(specification).isNotNull
+  }
+
+  @Test
+  fun `fails with unsupported task attribute in filters`() {
+    val filters = listOf(
+      "task.candidateUsers=foo"
+    )
+    val criteria = toCriteria(filters)
+
+    val error = assertThrows<IllegalArgumentException> {
+     criteria.toTaskSpecification()
+    }
+
+    assertThat(error.message).isEqualTo("JPA View found unsupported task attribute for equals comparison: candidateUsers.")
+  }
+
+  @Test
+  fun `fails with wrong value type for filter attribute`() {
+    val filters = listOf(
+      "task.priority=foo"
+    )
+    val criteria = toCriteria(filters)
+
+    val error = assertThrows<NumberFormatException> {
+      criteria.toTaskSpecification()
+    }
+
+    assertThat(error.message).isEqualTo("For input string: \"foo\"")
+  }
+
   @Test
   fun `creates multiple principal specifications`() {
     val spec = DataEntryRepository.isAuthorizedFor(
@@ -51,11 +94,19 @@ internal class SpecificationTest {
 
   @Test
   fun `creates a paged request`() {
-    val request = pageRequest(page = 15, size = 42, "+name")
-    assertThat(request.pageNumber).isEqualTo(15)
-    assertThat(request.pageSize).isEqualTo(42)
-    assertThat(request.sort.isSorted).isEqualTo(true)
-    assertThat(request.sort.isEmpty).isEqualTo(false)
+    val requestAsc = pageRequest(page = 15, size = 42, "+name")
+    assertThat(requestAsc.pageNumber).isEqualTo(15)
+    assertThat(requestAsc.pageSize).isEqualTo(42)
+    assertThat(requestAsc.sort.isSorted).isEqualTo(true)
+    assertThat(requestAsc.sort.isEmpty).isEqualTo(false)
+    assertThat(requestAsc.sort.getOrderFor("name")!!.direction).isEqualTo(Direction.ASC)
+
+    val requestDesc = pageRequest(page = 15, size = 42, "-name")
+    assertThat(requestDesc.pageNumber).isEqualTo(15)
+    assertThat(requestDesc.pageSize).isEqualTo(42)
+    assertThat(requestDesc.sort.isSorted).isEqualTo(true)
+    assertThat(requestDesc.sort.isEmpty).isEqualTo(false)
+    assertThat(requestDesc.sort.getOrderFor("name")!!.direction).isEqualTo(Direction.DESC)
 
     val unsorted = pageRequest(page = 14, size = 41, null)
     assertThat(unsorted.pageNumber).isEqualTo(14)
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepositoryITest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepositoryITest.kt
index 44b6d64d2..e501ebd7f 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepositoryITest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryRepositoryITest.kt
@@ -16,7 +16,6 @@ import org.camunda.bpm.engine.variable.Variables.createVariables
 import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
 import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
@@ -25,7 +24,6 @@ import org.springframework.data.repository.findByIdOrNull
 import org.springframework.test.annotation.DirtiesContext
 import org.springframework.test.context.ActiveProfiles
 import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.junit.jupiter.SpringExtension
 import java.time.Instant
 import java.util.*
 import javax.persistence.EntityManager
@@ -151,6 +149,13 @@ internal class DataEntryRepositoryITest {
     entityManager.flush()
   }
 
+  @Test
+  fun `loads each protocol entry only once`() {
+    entityManager.clear()
+    val dataEntry = dataEntryRepository.findByIdOrNull(dataEntry.dataEntryId)!!
+    assertThat(dataEntry.protocol.size).isEqualTo(1)
+  }
+
   @Test
   fun `should find data entry by id`() {
     val found = dataEntryRepository.findByIdOrNull(DataEntryId(entryType = dataEntry.dataEntryId.entryType, entryId = dataEntry.dataEntryId.entryId))
@@ -237,13 +242,13 @@ internal class DataEntryRepositoryITest {
   @Test
   fun `should find by filter payload attribute`() {
 
-    val byPayloadFilterByChildKeyNumberValue = dataEntryRepository.findAll(where(hasDataEntryPayloadAttribute("child.key-number", "42")))
+    val byPayloadFilterByChildKeyNumberValue = dataEntryRepository.findAll(where(hasDataEntryPayloadAttribute("child.key-number", listOf("42"))))
     assertThat(byPayloadFilterByChildKeyNumberValue).containsExactlyInAnyOrderElementsOf(listOf(dataEntry, dataEntry2))
 
     val byPayloadFilterByChildKeyValue =
       dataEntryRepository.findAll(
-        where(hasDataEntryPayloadAttribute("child.key", "value"))
-          .and(hasDataEntryPayloadAttribute("id", dataEntry.dataEntryId.entryId))
+        where(hasDataEntryPayloadAttribute("child.key", listOf("value")))
+          .and(hasDataEntryPayloadAttribute("id", listOf(dataEntry.dataEntryId.entryId)))
       )
     assertThat(byPayloadFilterByChildKeyValue).containsExactlyInAnyOrderElementsOf(listOf(dataEntry))
   }
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntityTest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntityTest.kt
index b37541307..4f059495e 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntityTest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntityTest.kt
@@ -8,7 +8,7 @@ import java.time.Instant
 internal class TaskEntityTest {
 
   @Test
-  internal fun `test toString`() {
+  fun `test toString`() {
     val now = Instant.now()
     val task = emptyTask().apply {
       taskId = "id-123"
diff --git a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepositoryITest.kt b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepositoryITest.kt
index 276bca861..272f32f52 100644
--- a/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepositoryITest.kt
+++ b/view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskRepositoryITest.kt
@@ -195,11 +195,11 @@ class TaskRepositoryITest {
 
   @Test
   fun `should find by payload attribute`() {
-    val result = taskRepository.findAll(hasTaskPayloadAttribute("complex.child2", "small"))
+    val result = taskRepository.findAll(hasTaskPayloadAttribute("complex.child2", listOf("small")))
     assertThat(result).hasSize(1)
     assertThat(result).containsExactlyInAnyOrder(task1)
 
-    val notfound = taskRepository.findAll(hasTaskPayloadAttribute("complex.child1", "13"))
+    val notfound = taskRepository.findAll(hasTaskPayloadAttribute("complex.child1", listOf("13")))
     assertThat(notfound).isEmpty()
   }
 
diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt
index b702ca181..fce9f3ffa 100755
--- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt
+++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt
@@ -49,10 +49,10 @@ abstract class PolyflowMongoServiceITestBase : SpringScenarioTest<PolyflowGivenS
       .and()
       .tasks_visible_to_candidate_group("muppetshow", listOf(expected))
       .and()
-      .query_updates_have_been_emitted(TasksForUserQuery(User("kermit", setOf("muppetshow"))), expected)
+      .query_updates_have_been_emitted(TasksForUserQuery(assignedToMeOnly = false, user = User("kermit", setOf("muppetshow"))), expected)
       .and()
       .query_updates_have_been_emitted(
-        TasksWithDataEntriesForUserQuery(User("kermit", setOf("muppetshow"))),
+        TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User("kermit", setOf("muppetshow"))),
         expected.withDataEntries()
       )
   }
@@ -75,7 +75,7 @@ abstract class PolyflowMongoServiceITestBase : SpringScenarioTest<PolyflowGivenS
       .task_is_created(TestTaskData(id = "some-id", assignee = "kermit").asTask())
       .and()
       .query_updates_have_been_emitted(
-        query = TasksForUserQuery(User("kermit", setOf("muppetshow"))),
+        query = TasksForUserQuery(assignedToMeOnly = false, user = User("kermit", setOf("muppetshow"))),
         TestTaskData(id = "some-id", assignee = "kermit").asTask()
       )
   }
@@ -162,7 +162,7 @@ abstract class PolyflowMongoServiceITestBase : SpringScenarioTest<PolyflowGivenS
 //      .and()
 //      .query_updates_have_been_emitted(TasksForUserQuery(User("gonzo", setOf("muppetshow"))), testTaskData.asTask().copy(candidateGroups = setOf("simpsons")))
       .and()
-      .query_updates_have_been_emitted(TasksForUserQuery(User("lisa", setOf("simpsons"))), testTaskData.asTask().copy(candidateGroups = setOf("simpsons")))
+      .query_updates_have_been_emitted(TasksForUserQuery(assignedToMeOnly = false, user = User("lisa", setOf("simpsons"))), testTaskData.asTask().copy(candidateGroups = setOf("simpsons")))
   }
 
   @Test
@@ -193,7 +193,7 @@ abstract class PolyflowMongoServiceITestBase : SpringScenarioTest<PolyflowGivenS
 //      .query_updates_have_been_emitted(TasksForUserQuery(kermit), TestTaskData(id = "some-id", candidateUsers = setOf("gonzo")).asTask())
       .and()
       .query_updates_have_been_emitted(
-        TasksForUserQuery(User("gonzo", setOf("muppets"))),
+        TasksForUserQuery(assignedToMeOnly = false, user = User("gonzo", setOf("muppets"))),
         TestTaskData(id = "some-id", candidateUsers = setOf("gonzo")).asTask()
       )
   }
@@ -215,7 +215,7 @@ abstract class PolyflowMongoServiceITestBase : SpringScenarioTest<PolyflowGivenS
     then()
       .task_does_not_exist("some-id")
       .and()
-      .query_updates_have_been_emitted(TasksForUserQuery(User("kermit", setOf("muppetshow"))), TestTaskData(id = "some-id", deleted = true).asTask())
+      .query_updates_have_been_emitted(TasksForUserQuery(assignedToMeOnly = false, user = User("kermit", setOf("muppetshow"))), TestTaskData(id = "some-id", deleted = true).asTask())
   }
 
 
diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowStages.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowStages.kt
index 8b4047940..ba5b08982 100644
--- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowStages.kt
+++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowStages.kt
@@ -157,7 +157,7 @@ class PolyflowThenStage<SELF : PolyflowThenStage<SELF>> : PolyflowStage<SELF>()
 
   @As("tasks with payload with ids \$taskIds are visible to \$user")
   fun tasks_with_payload_are_visible_to(user: User, vararg taskIds: String) = step {
-    val taskResponse = service.query(TasksWithDataEntriesForUserQuery(user = user, page = 1, size = 100)).join()
+    val taskResponse = service.query(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = user, page = 1, size = 100)).join()
     assertThat(taskResponse.elements.map { it.task.id }).containsExactlyElementsOf(taskIds.asIterable())
   }
 
@@ -191,17 +191,17 @@ class PolyflowThenStage<SELF : PolyflowThenStage<SELF>> : PolyflowStage<SELF>()
   }
 
   fun tasks_visible_to_assignee_or_candidate_user(username: String, expectedTasks: List<Task>) = step {
-    val result = service.query(TasksForUserQuery(User(username = username, groups = emptySet()))).join()
+    val result = service.query(TasksForUserQuery(assignedToMeOnly = false, user = User(username = username, groups = emptySet()))).join()
     assertThat(result.elements).containsExactlyElementsOf(expectedTasks)
   }
 
   fun data_entries_visible_to_user(username: String, expectedDataEntries: List<DataEntry>) = step {
-    val result = service.query(DataEntriesForUserQuery(User(username = username, groups = emptySet()))).join()
+    val result = service.query(DataEntriesForUserQuery(user = User(username = username, groups = emptySet()))).join()
     assertThat(result.elements).containsExactlyElementsOf(expectedDataEntries)
   }
 
   fun tasks_visible_to_candidate_group(groupName: String, expectedTasks: List<Task>) = step {
-    val result = service.query(TasksForUserQuery(User(username = "<unmet>", groups = setOf(groupName)))).join()
+    val result = service.query(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "<unmet>", groups = setOf(groupName)))).join()
     assertThat(result.elements).containsExactlyElementsOf(expectedTasks)
   }
 
@@ -237,7 +237,7 @@ class PolyflowThenStage<SELF : PolyflowThenStage<SELF>> : PolyflowStage<SELF>()
   }
 
   fun task_is_not_found_for_user(taskId: String, assignee: String) = step {
-    val result = service.query(TasksForUserQuery(User(assignee, setOf()))).join()
+    val result = service.query(TasksForUserQuery(assignedToMeOnly = false, user = User(assignee, setOf()))).join()
     assertThat(result.elements.map { it.id }).doesNotContain(taskId)
   }
 
diff --git a/view/simple/src/test/kotlin/io/holunda/polyflow/view/simple/service/TaskPoolStages.kt b/view/simple/src/test/kotlin/io/holunda/polyflow/view/simple/service/TaskPoolStages.kt
index 732b273fe..8e30fad6c 100644
--- a/view/simple/src/test/kotlin/io/holunda/polyflow/view/simple/service/TaskPoolStages.kt
+++ b/view/simple/src/test/kotlin/io/holunda/polyflow/view/simple/service/TaskPoolStages.kt
@@ -102,8 +102,8 @@ class SimpleTaskPoolWhenStage<SELF : SimpleTaskPoolWhenStage<SELF>> : AbstractSi
   @ProvidedScenarioState(resolution = ScenarioState.Resolution.NAME)
   private var returnedTasksForApplication = TaskQueryResult(listOf())
 
-  private fun query(page: Int, size: Int) = TasksWithDataEntriesForUserQuery(User("kermit", setOf()), page, size)
-  private fun filterQuery(sort: String, filters: List<String>) = TasksForUserQuery(user = User("kermit", setOf()), filters = filters, sort = sort)
+  private fun query(page: Int, size: Int) = TasksWithDataEntriesForUserQuery(User("kermit", setOf()), true, page, size)
+  private fun filterQuery(sort: String, filters: List<String>) = TasksForUserQuery(assignedToMeOnly = false, user = User("kermit", setOf()), filters = filters, sort = sort)
 
   @As("Page $ is queried with a page size of $")
   fun page_is_queried(page: Int, size: Int) = step {
@@ -122,7 +122,7 @@ class SimpleTaskPoolWhenStage<SELF : SimpleTaskPoolWhenStage<SELF>> : AbstractSi
 
   @As("Tasks are queried with filter $")
   fun tasks_are_queried(filters: List<String>) = step {
-    queriedTasks.addAll(simpleTaskPoolService.query(filterQuery("+name", filters)).elements.map { TaskWithDataEntries(it) })
+    queriedTasks.addAll(simpleTaskPoolService.query(filterQuery("+createdDate", filters)).elements.map { TaskWithDataEntries(it) })
   }
 
   @As("All tasks are queried with filter $")
@@ -214,7 +214,7 @@ class SimpleTaskPoolThenStage<SELF : SimpleTaskPoolThenStage<SELF>> : AbstractSi
   }
 
   fun task_is_not_found_for_user(userId: String, taskId: String) = step {
-    val result = simpleTaskPoolService.query(TasksForUserQuery(User(userId, setOf())))
+    val result = simpleTaskPoolService.query(TasksForUserQuery(assignedToMeOnly = false, user = User(username = userId, groups = setOf())))
     assertThat(result.elements.map { it.id }).doesNotContain(taskId)
   }
 
diff --git a/view/view-api/src/test/kotlin/query/PageableSortableQueryTest.kt b/view/view-api/src/test/kotlin/query/PageableSortableQueryTest.kt
new file mode 100644
index 000000000..7d8698c0a
--- /dev/null
+++ b/view/view-api/src/test/kotlin/query/PageableSortableQueryTest.kt
@@ -0,0 +1,74 @@
+package io.holunda.polyflow.view.query
+
+import io.holunda.polyflow.view.DataEntry
+import io.holunda.polyflow.view.Task
+import io.holunda.polyflow.view.auth.User
+import io.holunda.polyflow.view.query.data.DataEntriesQuery
+import io.holunda.polyflow.view.query.task.AllTasksQuery
+import io.holunda.polyflow.view.query.task.TasksWithDataEntriesForGroupQuery
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import kotlin.reflect.full.declaredMemberProperties
+
+internal class PageableSortableQueryTest {
+
+  private val createTimeAsc = "+createTime"
+  private val nameDesc = "-name"
+  private val badField = "+someTaskField"
+  private val badOrdering = "*createTime"
+  private val user = User(username = "kermit", groups = setOf())
+
+  @Test
+  fun should_sanitize_task_query() {
+    assertThat(AllTasksQuery(sort = createTimeAsc).apply { sanitizeSort(Task::class) }.sort).isEqualTo(createTimeAsc)
+    assertThat(AllTasksQuery(sort = null).apply { sanitizeSort(Task::class) }.sort).isNull()
+    val badFieldException = assertThrows<IllegalArgumentException> { AllTasksQuery(sort = badField).apply { sanitizeSort(Task::class) } }
+    assertThat(badFieldException.message).isEqualTo(
+      "Sort parameter must be one of ${Task::class.declaredMemberProperties.joinToString(", ") { it.name }} but it was ${
+        badField.substring(
+          1
+        )
+      }."
+    )
+
+    val badOperatorException = assertThrows<IllegalArgumentException> { AllTasksQuery(sort = badOrdering).apply { sanitizeSort(Task::class) } }
+    assertThat(badOperatorException.message).isEqualTo("Sort must start either with '+' or '-' but it was starting with '*'")
+  }
+
+  @Test
+  fun should_sanitize_task_with_dataentry_query() {
+    assertThat(TasksWithDataEntriesForGroupQuery(user = user, sort = createTimeAsc).apply { sanitizeSort(Task::class) }.sort).isEqualTo(createTimeAsc)
+    assertThat(TasksWithDataEntriesForGroupQuery(user = user, sort = null).apply { sanitizeSort(Task::class) }.sort).isNull()
+    val badFieldException =
+      assertThrows<IllegalArgumentException> { TasksWithDataEntriesForGroupQuery(user = user, sort = badField).apply { sanitizeSort(Task::class) } }
+    assertThat(badFieldException.message).isEqualTo(
+      "Sort parameter must be one of ${Task::class.declaredMemberProperties.joinToString(", ") { it.name }} but it was ${
+        badField.substring(
+          1
+        )
+      }."
+    )
+
+    val badOperatorException =
+      assertThrows<IllegalArgumentException> { TasksWithDataEntriesForGroupQuery(user = user, sort = badOrdering).apply { sanitizeSort(Task::class) } }
+    assertThat(badOperatorException.message).isEqualTo("Sort must start either with '+' or '-' but it was starting with '*'")
+  }
+
+  @Test
+  fun should_sanitize_dataentry_query() {
+    assertThat(DataEntriesQuery(sort = nameDesc).apply { sanitizeSort(DataEntry::class) }.sort).isEqualTo(nameDesc)
+    assertThat(DataEntriesQuery(sort = null).apply { sanitizeSort(DataEntry::class) }.sort).isNull()
+    val badFieldException = assertThrows<IllegalArgumentException> { DataEntriesQuery(sort = badField).apply { sanitizeSort(DataEntry::class) } }
+    assertThat(badFieldException.message).isEqualTo(
+      "Sort parameter must be one of ${DataEntry::class.declaredMemberProperties.joinToString(", ") { it.name }} but it was ${
+        badField.substring(
+          1
+        )
+      }."
+    )
+
+    val badOperatorException = assertThrows<IllegalArgumentException> { DataEntriesQuery(sort = badOrdering).apply { sanitizeSort(DataEntry::class) } }
+    assertThat(badOperatorException.message).isEqualTo("Sort must start either with '+' or '-' but it was starting with '*'")
+  }
+}
diff --git a/view/view-api/src/test/kotlin/query/task/TaskWithDataEntriesForUserQueryTest.kt b/view/view-api/src/test/kotlin/query/task/TaskWithDataEntriesForUserQueryTest.kt
index 994cd0be8..74f8ccaca 100644
--- a/view/view-api/src/test/kotlin/query/task/TaskWithDataEntriesForUserQueryTest.kt
+++ b/view/view-api/src/test/kotlin/query/task/TaskWithDataEntriesForUserQueryTest.kt
@@ -38,10 +38,10 @@ class TaskWithDataEntriesForUserQueryTest {
 
   @Test
   fun `should filter by user`() {
-    assertThat(TasksWithDataEntriesForUserQuery(user = User(username = "kermit", groups = setOf("muppets"))).applyFilter(taskWithDataEntries)).isTrue
-    assertThat(TasksWithDataEntriesForUserQuery(user = User(username = "kermit", groups = setOf())).applyFilter(taskWithDataEntries)).isTrue
-    assertThat(TasksWithDataEntriesForUserQuery(user = User(username = "piggy", groups = setOf())).applyFilter(taskWithDataEntries)).isTrue
-    assertThat(TasksWithDataEntriesForUserQuery(user = User(username = "ironman", groups = setOf("muppets"))).applyFilter(taskWithDataEntries)).isTrue
-    assertThat(TasksWithDataEntriesForUserQuery(user = User(username = "ironman", groups = setOf("avengers"))).applyFilter(taskWithDataEntries)).isFalse
+    assertThat(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User(username = "kermit", groups = setOf("muppets"))).applyFilter(taskWithDataEntries)).isTrue
+    assertThat(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User(username = "kermit", groups = setOf())).applyFilter(taskWithDataEntries)).isTrue
+    assertThat(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User(username = "piggy", groups = setOf())).applyFilter(taskWithDataEntries)).isTrue
+    assertThat(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User(username = "ironman", groups = setOf("muppets"))).applyFilter(taskWithDataEntries)).isTrue
+    assertThat(TasksWithDataEntriesForUserQuery(assignedToMeOnly = false, user = User(username = "ironman", groups = setOf("avengers"))).applyFilter(taskWithDataEntries)).isFalse
   }
 }
diff --git a/view/view-api/src/test/kotlin/query/task/TasksForUserQueryTest.kt b/view/view-api/src/test/kotlin/query/task/TasksForUserQueryTest.kt
index cb9b7a3d3..e93c4819c 100644
--- a/view/view-api/src/test/kotlin/query/task/TasksForUserQueryTest.kt
+++ b/view/view-api/src/test/kotlin/query/task/TasksForUserQueryTest.kt
@@ -25,10 +25,10 @@ class TasksForUserQueryTest {
 
   @Test
   fun `should filter by user`() {
-    assertThat(TasksForUserQuery(user = User(username = "kermit", groups = setOf("muppets"))).applyFilter(task)).isTrue
-    assertThat(TasksForUserQuery(user = User(username = "kermit", groups = setOf())).applyFilter(task)).isTrue
-    assertThat(TasksForUserQuery(user = User(username = "piggy", groups = setOf())).applyFilter(task)).isTrue
-    assertThat(TasksForUserQuery(user = User(username = "ironman", groups = setOf("muppets"))).applyFilter(task)).isTrue
-    assertThat(TasksForUserQuery(user = User(username = "ironman", groups = setOf("avengers"))).applyFilter(task)).isFalse
+    assertThat(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "kermit", groups = setOf("muppets"))).applyFilter(task)).isTrue
+    assertThat(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "kermit", groups = setOf())).applyFilter(task)).isTrue
+    assertThat(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "piggy", groups = setOf())).applyFilter(task)).isTrue
+    assertThat(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "ironman", groups = setOf("muppets"))).applyFilter(task)).isTrue
+    assertThat(TasksForUserQuery(assignedToMeOnly = false, user = User(username = "ironman", groups = setOf("avengers"))).applyFilter(task)).isFalse
   }
 }