840: Support a form flow as start form of a building block - #886
Draft
maarten-ritense wants to merge 10 commits into
Draft
840: Support a form flow as start form of a building block#886maarten-ritense wants to merge 10 commits into
maarten-ritense wants to merge 10 commits into
Conversation
An action that starts a building block ran the newest version of that building block instead of the version linked to the case, failing when that version wrote to fields the linked version does not have. The process link carries the exact, versioned process definition id, but form submission forwarded only the process definition key. Resolving a key then fell back to "highest engine version not linked to a case definition", which does not exclude building-block-owned definitions, so a newer draft version won. Carry the versioned id through to the engine for process-link starts, and derive a document's blueprint as case or building block - caseDefinitionId() is null for building block documents, which is what made the lookup degrade to "latest". Resolving by key alone now refuses building-block definitions instead of guessing a version. processDefinitionId on the start-process requests is @JsonIgnore on purpose: ProcessDocumentResource binds two of them from client JSON with FAIL_ON_UNKNOWN_PROPERTIES disabled, so a bindable field would let a caller bypass key and blueprint resolution and reach a suspended draft or another case's definition.
13.40.0 is being released, so the entry moves to the next unreleased minor. Adds the 13.41.0 directory and registers it in SUMMARY.md so GitBook renders it.
Resolving the start form threw a NullPointerException. The form flow definition was looked up through the case-definition link, but a building block's main process has no such link row: only CD: blueprints get one on deploy. Resolution now falls back to the blueprint from the process definition's version tag, which covers both case definitions and building blocks. This replaces the openTask fallback on findDefinitionByKey too, which broke as soon as two building block versions owned a form flow with the same key. The form flow instance now also carries the process definition id, so submitting starts the building block version linked to the case. A key cannot identify a version, because every building block version redeploys the same key. Finally, startProcessForDocument no longer overwrites an existing process document association. A building block's start event listener creates the building block document and points the association at it while the process starts, which made the subsequent association fail. modifyDocumentAndStartProcess already guarded against this, which is why a form.io start form did work.
Both the URL process link and the form.io submission path dereferenced the case-definition link without a null check, so they would fail the same way as the form flow start form for a building-block-owned process. They now fall back to the blueprint from the process definition's version tag. Dormant until now, because both only reach this code when neither a document nor a document definition name is supplied.
Add the release note for the building block start form, and document the three valtimoFormFlow expressions with the linking context each one belongs to. The form flow page only showed completeTask, so copying its complete example onto a start event fails at runtime with an unclear error.
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
maarten-ritense
changed the base branch from
bugfix/819-actions-respect-building-block-versions
to
next-minor
August 6, 2026 10:02
…o bugfix/840-form-flow-start-form-building-block # Conflicts: # documentation/release-notes/13.x.x/13.41.0/README.md
18 tasks
The specification that resolves a process definition from its key alone was written out three times: in OperatonProcessService, inlined in ProcessAuthorizationService and mirrored in the helper's integration test. Move it to OperatonProcessDefinitionSpecificationHelper so all three share one definition and the test covers the real specification.
…o bugfix/840-form-flow-start-form-building-block
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Describe the changes
Link to the related Github issue: generiekzaakafhandelcomponent/gzac-issues#840
Important
Depends on #879 — please review and merge that one first. This branch is built on top of
bugfix/819-actions-respect-building-block-versionsbecause it needsStartProcessForDocumentRequest.withProcessDefinitionIdfrom it.Until #879 merges, this PR's diff against
next-minoralso contains its commits. Only the three840:commits (11 files) belong to this change; the diff collapses to those once #879 is merged. Everything below concerns issue 840 only.A form flow configured as the start form of a building block's main process never worked. Starting that building block from the actions of a case failed before the form even opened. The same setup with a form.io start form did work, which is why this went unnoticed.
Three defects sit on that one path, each hidden behind the previous one.
1. Resolving the start form threw a
NullPointerException.FormFlowProcessLinkActivityHandler.getStartEventObjectresolved the form flow definition through the case-definition link, andProcessDefinitionCaseDefinitionService.findByProcessDefinitionIdends in!!. A building block's main process has noprocess_definition_case_definitionrow: it is owned by a building block, andOperatonProcessService.deployonly creates link rows forCD:blueprints — there is an explicit TODO about that atOperatonProcessService.java:622. SoGET /api/v1/process-definition/{processDefinitionId}/start-formthrew and no start form opened.Resolution now falls back to the blueprint encoded in the process definition's version tag.
OperatonProcessDefinition.getBlueprintId()already parses bothBB:andCD:tags, andFormFlowServicealready has thefindDefinitionOrNull(key, BuildingBlockDefinitionId)overload, so the fallback reuses what is there rather than adding a lookup.2. The building block version was lost on submit. The handler put only the process definition key into the form flow instance's additional properties, and
ValtimoFormFlow.startCase/startSupportingProcessbuilt a key-onlyStartProcessForDocumentRequest, so the form flow submission path never carried the version. Every building block version redeploys the same process definition key under a new engine version, so a key cannot identify a version. The instance now carriesprocessDefinitionIdand passes it on withwithProcessDefinitionId(...), so the version the start form was opened for is the version that starts.3. The process document association clashed. Not in the issue — found while writing the regression test, with the first two defects already fixed. Submitting still failed with
IllegalStateException: Process was already associated with another document.startProcessForDocumentunconditionally created a process document association, butBuildingBlockStartEventListenerhas already created the building block document, pointed the association at it and rewritten the business key while the process starts. Its siblingmodifyDocumentAndStartProcessalready guarded this withfindProcessDocumentInstance(...).isEmpty()— which is exactly why a form.io start form worked and a form flow did not. The guard is now on both.Specify the code branch location:
bugfix/840-form-flow-start-form-building-block→bugfix/819-actions-respect-building-block-versions(#879)Relevant comments:
Breaking changes
No signature, constructor or JSON contract changed; all new methods are private. One behavioural change worth calling out:
startProcessForDocumentno longer throws when the process instance is already associated with a different document, it leaves that association in place. The only thing that can create an association in that window is a listener running during the start, andmodifyDocumentAndStartProcesshas always behaved this way — so this removes a divergence rather than introducing one. The other four callers (UploadProcessService,VerzoekPluginEventListener,BezwaarAdHocFvmStartFormSubmissionHandler,ValtimoFormFlow) never relied on the exception.Documentation
New features or changes that have been introduced have been documented.
documentation/features/case/form-flow.mdgained a "Completing a form flow" section covering the threevaltimoFormFlowexpressions, the linking context each requires, theinstance.idversusstep.submissionDatadifference, and the fact thatdoc:writes to the case document rather than the building block document. The complete example is now labelled as a user-task form flow.Tests
Unit tests have been added that cover these changes
URLProcessLinkServiceTestandDefaultFormSubmissionServiceTesteach gained a case proving the blueprint fallback resolves a document definition name when there is no case-definition link.FormFlowProcessLinkActivityHandlerIntTestadditionally assertsprocessDefinitionIdis on the instance for the existing case-scoped path.Integration tests have been added that cover these changes
BuildingBlockStartFormFlowIT(new) covers the whole flow: a building-block-scoped form flow on the main process start event, the building block linked to a case, a newer building block version deployed so both share one process definition key, thengetStartEventObject→completeStep, asserting the started instance runs the linked version and that exactly oneBuildingBlockInstanceexists at that version for the case document. Its ability to catch each of the three defects was verified individually — see Relevant comments.Ran green: full backend
./gradlew test, andintegrationTestingPostgresqlforbuilding-block,form-flow,process-document,process-link-url,form,case,form-view-model,zgw:verzoekandzgw:zaken-api— the last four because they are the other callers ofstartProcessForDocumentand of the two hardened resolution paths. Checkstyle passes on the touched modules with no new warnings.Describe the testing steps
${valtimoFormFlow.startSupportingProcess(instance.id, {...})}on the last stepNullPointerExceptionin the log)Security
The Secure by Design principle has been applied to these changes
The new
processDefinitionIdis populated server-side only and never bindable from a request, as described under Relevant comments — this matters because it selects which process definition gets started for a document. The association guard is narrow: it only declines to overwrite an association created moments earlier during the same start, and the association it preserves is the correct one (a building block process's business key is its own document, not the case document).Added or changed REST API endpoints have authentication and authorization in place
No endpoints were added or changed, and no request or response DTO changed.
Valtimo access control checks have been implemented
The existing check in
ProcessLinkActivityService.getStartEventObject—RelatedEntityAuthorizationRequest(OperatonExecution, CREATE, OperatonProcessDefinition, processLink.processDefinitionId)— is unchanged. The id this change carries through to the start is that same process definition id, so the definition that is started and the definition that was authorized now agree by construction, and permission rules keyed onversionTagsee the linked building block version.One pre-existing gap is left as it was and is not made worse:
ValtimoFormFlow.startSupportingProcessstill callsstartProcessForDocumentinsiderunWithoutAuthorization, under a//TODO: PBAC START/CREATE checkthat predates this change. Authorization for this flow therefore still happens when the start form is opened rather than when it is submitted.Dependencies
Newly added dependencies do not introduce known vulnerabilities/CVE's and are in line with the Valtimo license
No dependencies were added or changed.