---
title: Process (PR) — Layer 4
aliases: [PR, process, processflow, orchestration]
sources:
    [sources/sessions/2026-02-18-process-analysis.md, sources/sessions/2026-04-20-process-patterns-and-context-menus.md]
last_updated: 2026-04-28
status: draft
---

# Process (PR) — Layer 4

Processes orchestrate the application flow — they coordinate BO/LO loading, execute business logic, make decisions, and display UI screens.

## Overview

Processes serve as the orchestration layer that:

-   Coordinate loading and saving of Business Objects and ListObjects
-   Define navigation flow between screens
-   Implement decision logic and conditional branching
-   Execute business logic methods at the right time
-   Manage process-level state and variables (ProcessContext)
-   Connect the business layer (BO/LO) to the presentation layer (UI)
-   Invoke sub-processes and return values to callers

## XML Structure

```xml
<Process name="Visit::InfoProcess" defaultAction="showVisitInfo"
         schemaVersion="0.0.0.5">
  <Entry>
    <ProcessContext>
      <Declarations>
        <Declaration name="VisitBo" type="BoVisit" />
        <Declaration name="ContextMenuList" type="LoVisitContextMenu" />
      </Declarations>
      <Parameters>
        <Input name="VisitPKey" type="DomPKey" />
      </Parameters>
    </ProcessContext>
    <EntryActions>
      <Action name="loadVisit" actionType="LOAD" type="BoVisit">
        <Parameters>
          <Input name="pKey" value="ProcessContext::VisitPKey" />
        </Parameters>
        <Return name="ProcessContext::VisitBo" />
      </Action>
    </EntryActions>
  </Entry>
  <Body>
    <Actions>
      <Action actionType="VIEW" name="showVisitInfo">
        <UIDescription>Visit::InfoUI</UIDescription>
        <Events>
          <Event name="startVisit" action="HandleStartVisit" />
        </Events>
      </Action>
    </Actions>
  </Body>
</Process>
```

## Action Types

| Action Type    | Purpose                        | Key Attributes                                     |
| -------------- | ------------------------------ | -------------------------------------------------- |
| **VIEW**       | Display a UI screen            | `<UIDescription>`, `<Events>`                      |
| **LOAD**       | Load a BO or LO                | `type`, `<Parameters>`, `<Return>`                 |
| **CREATE**     | Create an empty BO or LO       | `type`, `<Parameters>`, `<Return>`                 |
| **SAVE**       | Persist a BO or LO             | `<Parameters>`                                     |
| **LOGIC**      | Execute a BO/LO/utility method | `call`, `<Parameters>`, `<Return>`                 |
| **DECISION**   | Conditional branching          | `parameter`, `<Case>`, `<CaseElse>`, `<CaseEmpty>` |
| **CONFIRM**    | User confirmation dialog       | `confirmType`, `<Message>`, `<Cases>`              |
| **VALIDATION** | Validate a BO                  | `<Validations>`                                    |
| **PROCESS**    | Invoke a sub-process           | `process`, `<Parameters>`, `<ReturnValues>`        |
| **END**        | Terminate process              | `<ReturnValues>` (optional)                        |

## DECISION Patterns

### On BO Property (Status Routing)

```xml
<Action name="StatusDecision" actionType="DECISION"
        parameter="ProcessContext::VisitBo.status">
  <Case value="Completed" action="ShowCompletedView" />
  <Case value="InProgress" action="ShowInProgressView" />
  <CaseElse action="ShowPlannedView" />
  <CaseEmpty action="HandleNoStatus" />
</Action>
```

### On Boolean Flag

```xml
<Action name="IsReadOnly" actionType="DECISION"
        parameter="ProcessContext::isReadOnly">
  <Case value="1" action="ShowReadOnlyView" />
  <CaseElse action="ShowEditView" />
</Action>
```

### On Event Property (Context Menu Selection)

```xml
<Action name="ContextMenu_Decision" actionType="DECISION"
        parameter="Event.selected">
  <Case value="Execute" action="LoadDetail" />
  <Case value="Cancel" action="CancelItem" />
  <Case value="Delete" action="DeleteItem" />
  <Case value="Copy" action="CopyItem" />
  <CaseElse action="ShowList" />
  <CaseEmpty action="ShowList" />
</Action>
```

### Multi-Value with Nested Decisions

```xml
<Action name="PhaseDecision" actionType="DECISION"
        parameter="ProcessContext::MainBO.phase">
  <Case value="Released" action="HandleReleased" />
  <Case value="Canceled" action="HandleReleased" />
  <Case value="Ready" action="HandleReleased" />
  <CaseElse action="NextDecision" />
</Action>
```

## CONFIRM Patterns

### YesNo

```xml
<Action name="ConfirmDelete" actionType="CONFIRM" confirmType="YesNo">
  <Message messageId="ConfirmDeleteMessage" />
  <Cases>
    <Case value="Yes" action="DoDelete" />
    <Case value="No" action="CancelDelete" />
  </Cases>
</Action>
```

### Ok (Acknowledgment)

```xml
<Action actionType="CONFIRM" confirmType="Ok" name="ShowError">
  <Message messageId="ErrorMessage" />
  <Cases>
    <Case value="Ok" action="ReturnToView" />
  </Cases>
</Action>
```

### YesNoCancel

```xml
<Action actionType="CONFIRM" confirmType="YesNoCancel" name="ConfirmSave">
  <Message messageId="ConfirmSaveChanges" />
  <Cases>
    <Case value="Yes" action="SaveAndClose" />
    <Case value="No" action="DiscardAndClose" />
  </Cases>
</Action>
```

## Sub-Process Invocation (PROCESS Action)

```xml
<Action actionType="PROCESS" name="OpenLookup"
        process="Customer::LookupProcess">
  <Parameters>
    <Input name="ReferenceUserPKey" value="ProcessContext::ResponsiblePKey" />
  </Parameters>
  <ReturnValues>
    <Return name="ProcessContext::CustomerPKey" value="customerPKey" />
    <Return name="ProcessContext::SubstitutedPKey" value="substitutedUsrPKey" />
  </ReturnValues>
  <TransitionTo action="ProcessReturnedValues" />
</Action>
```

-   `process="Module::ProcessName"` — fully qualified process name
-   `<ReturnValues>` maps child process END ReturnValues back to parent's ProcessContext

## END Action (Returning Values to Caller)

```xml
<Action actionType="END" name="EndWithRefresh">
  <ReturnValues>
    <Return name="refreshRequired" type="Literal" value="1" />
    <Return name="createdPKey" value="ProcessContext::NewBo.pKey" />
  </ReturnValues>
</Action>
```

## LOGIC Action Patterns

### Call BO Method with Parameters

```xml
<Action actionType="LOGIC" name="StartVisit"
        call="ProcessContext::VisitBo.startVisit">
  <TransitionTo action="SaveVisit" />
</Action>
```

### Call BO Method with Input/Return

```xml
<Action actionType="LOGIC" name="ValidateTasks"
        call="ProcessContext::TaskList.checkForIncompleteMandatory">
  <Parameters>
    <Input name="status" value="ProcessContext::TargetStatus" />
  </Parameters>
  <Return name="ProcessContext::ValidationResult" />
  <TransitionTo action="ValidationDecision" />
</Action>
```

### Utility Methods

```xml
<!-- Utils.identity: assign a value to ProcessContext -->
<Action actionType="LOGIC" name="SetFlag" call="Utils.identity">
  <Parameters>
    <Input name="value" value="1" type="Literal" />
  </Parameters>
  <Return name="ProcessContext::DataLoaded" />
  <TransitionTo action="NextAction" />
</Action>

<!-- Utils.isDefined: check if value exists -->
<Action actionType="LOGIC" name="CheckValue" call="Utils.isDefined">
  <Parameters>
    <Input name="value" value="ProcessContext::SomeVar" />
  </Parameters>
  <Return name="ProcessContext::IsValueDefined" />
  <TransitionTo action="DefinedDecision" />
</Action>

<!-- Utils.createAnsiToday: get current date -->
<Action actionType="LOGIC" name="GetToday" call="Utils.createAnsiToday">
  <Return name="ProcessContext::CurrentDate" />
</Action>
```

## Event Handling

### VIEW with Multiple Events

```xml
<Action name="ShowList" actionType="VIEW">
  <UIDescription>Visit::CalendarUI</UIDescription>
  <Events>
    <Event name="itemSelected" action="LoadDetail" />
    <Event name="createNew" action="CreateWizard" />
    <Event name="contextMenuOpening" action="GetContextMenu" />
    <Event name="contextMenuItemSelected" action="ContextMenu_Decision" />
    <Event name="swipeEvent" action="HandleSwipe" />
    <Event name="filterChanged" action="ApplyFilter" />
  </Events>
</Action>
```

### Event.\* Parameters

Events pass properties from the UI item that triggered them:

```xml
<!-- Context menu passes multiple item properties -->
<Action actionType="LOAD" name="GetContextMenu" type="LoContextMenu">
  <Parameters>
    <Input name="pKey" value="Event.pKey" />
    <Input name="status" value="Event.visitStatus" />
    <Input name="syncStatus" value="Event.syncStatus" />
  </Parameters>
  <Return name="ProcessContext::ContextMenuList" />
</Action>
```

UI defines which properties are available via `<Params>`:

```xml
<ContextOpeningEvent event="contextMenuOpening">
  <Params>
    <Param name="pKey" value=".pKey" />
    <Param name="visitStatus" value=".status" />
  </Params>
</ContextOpeningEvent>
```

## Context Menu Implementation

See [[cockpit-cards]] for the cockpit card variant. For standalone lists:

### Process Flow

```
contextMenuOpening event → LOAD Lo*ContextMenu (with Event.* params)
                         → BL builds menu items conditionally
                         → returns to ProcessContext::ContextMenuList
contextMenuItemSelected  → DECISION on Event.selected
                         → Routes to appropriate action per menu item
```

### Context Menu LO Structure (empty DS, items built in BL)

The DS returns `undefined` — all items are built programmatically:

```javascript
var contextMenuItemList = [];
contextMenuItemList.push({
    id: '0000001',
    actionImg: 'ExecuteDarkGrey24',
    actionId: 'Execute',
    processEvent: 'Execute',
    actionEnabled: isAllowed ? '1' : '0',
    actionVisible: '1',
});
me.addItems(contextMenuItemList);
```

### UI Wiring

```xml
<ContextMenu>
  <Bindings>
    <Binding target="DataSource"
             binding="ProcessContext::ContextMenuList.Items[]"
             bindingMode="ONE_WAY" />
  </Bindings>
  <Items name="ContextMenuItems">
    <Bindings>
      <Binding target="Icon" type="Image" binding=".actionImg" />
      <Binding target="Text" type="Label" binding=".actionId" />
      <Binding type="Editable" target="Editable" binding=".actionEnabled" />
    </Bindings>
  </Items>
</ContextMenu>
```

## Common Process Patterns

| Pattern            | Flow                                                                    | Use Case               |
| ------------------ | ----------------------------------------------------------------------- | ---------------------- |
| **Load & View**    | LOAD → VIEW                                                             | Display detail         |
| **Create Wizard**  | CREATE → VIEW → VALIDATE → DECISION → SAVE → END                        | New record             |
| **Edit & Save**    | LOAD → VIEW → VALIDATE → DECISION → SAVE                                | Edit existing          |
| **Status Change**  | LOAD → LOGIC (check) → DECISION → CONFIRM → LOGIC (change) → SAVE → END | Complete/cancel        |
| **Lazy Card Load** | CREATE (empty) → CardLoadEvent → LOGIC (load) → LOGIC (info)            | Cockpit cards          |
| **Context Menu**   | VIEW (events) → LOAD menu → DECISION → action per case                  | Right-click/long-press |
| **Sub-Process**    | PROCESS → ReturnValues → DECISION → continue                            | Lookup, wizard         |

## Process Lifecycle

```
Caller invokes process with parameters
    ↓
ProcessContext initialized (Declarations empty, Parameters populated)
    ↓
EntryActions execute sequentially (LOAD, CREATE, LOGIC)
    ↓
defaultAction in Body executes (typically VIEW)
    ↓
User interacts → Events trigger → Actions chain via TransitionTo
    ↓
Process reaches END action (optionally returns values to caller)
```

## Build-Critical Syntax Rules

### `<EntryActions>` Element Is Mandatory

Inside `<Entry>`, the schema requires **both** `<ProcessContext>` **and** `<EntryActions>` as siblings. Omitting `<EntryActions>` — even when the process has no work to do before its body — fails the build with validator code `00000001`:

```
Element 'Entry': Missing child element(s). Expected is ( EntryActions )
```

Use the self-closing form when the process has no entry actions:

```xml
<!-- CORRECT — chooser / menu-only process with no entry work -->
<Entry>
  <ProcessContext>
    <Declarations/>
  </ProcessContext>
  <EntryActions/>
</Entry>

<!-- WRONG — build error 00000001 -->
<Entry>
  <ProcessContext>
    <Declarations/>
  </ProcessContext>
</Entry>
```

Every `.processflow.xml` in `src/` contains an `<EntryActions>` element (either populated or self-closing). Confirm with `grep -L '<EntryActions' src/**/*.processflow.xml` before building — any file in the output list will fail validation.

### CONFIRM Message Element

The `<Message>` element accepts only `messageId`. The `messageDefault` attribute does **not exist** and will fail the build:

```xml
<!-- CORRECT -->
<Action name="ConfirmDelete" actionType="CONFIRM" confirmType="YesNo">
  <Message messageId="CasConfirmDeletionMsg" />
  <Cases>
    <Case value="Yes" action="DoDelete" />
    <Case value="No" action="ShowDetail" />
  </Cases>
</Action>

<!-- WRONG — will fail build -->
<Message messageId="CasConfirmDeletionMsg" messageDefault="Delete this item?" />
```

The message text is defined in localization resources, not inline in the process XML.

### CONFIRM Types

| confirmType   | Buttons         | Case Values                 |
| ------------- | --------------- | --------------------------- |
| `YesNo`       | Yes, No         | `"Yes"`, `"No"`             |
| `Ok`          | Ok              | `"Ok"`                      |
| `YesNoCancel` | Yes, No, Cancel | `"Yes"`, `"No"`, `"Cancel"` |

## Runtime Pitfalls

### ProcessContext Variables Must Be Initialized Before VIEW

Any ProcessContext variable bound to a UI control must have a value before the VIEW action executes. If a variable is declared but never assigned, UI controls that bind to it will receive `null`, causing runtime crashes — especially for controls that parse the value (CalendarControl, DatePicker, etc.).

**Common symptom:** `Cannot read properties of null` errors in the browser console immediately after navigating to a process.

**Fix:** Initialize all UI-bound variables in EntryActions using `Utils.createAnsiDateToday`, `Utils.identity`, or direct LOAD/CREATE actions:

```xml
<EntryActions>
  <!-- Initialize date for CalendarControl -->
  <Action name="InitDate" actionType="LOGIC" call="Utils.createAnsiDateToday">
    <Return name="ProcessContext::CurrentDate" />
  </Action>
  <!-- Initialize string for header binding -->
  <Action name="InitHeader" actionType="LOGIC" call="Utils.identity">
    <Parameters>
      <Input name="value" value="Default Title" type="Literal" />
    </Parameters>
    <Return name="ProcessContext::HeaderText" />
  </Action>
</EntryActions>
```

This is especially critical when creating a new process entry point (e.g., from a menu item) that doesn't receive input parameters — unlike sub-processes that get values passed from their caller.

## Best Practices

| Do                                                          | Don't                                              |
| ----------------------------------------------------------- | -------------------------------------------------- |
| Initialize all UI-bound ProcessContext vars in EntryActions | Leave declared variables uninitialized before VIEW |
| Load data in EntryActions (before UI)                       | Load data after VIEW action                        |
| Use descriptive action names                                | Name actions "Action1", "DoStuff"                  |
| Use explicit `<TransitionTo>`                               | Rely on implicit flow                              |
| Use `type="Literal"` for string constants                   | Pass raw strings without type                      |
| Use `CaseElse` and `CaseEmpty` in DECISIONs                 | Leave unhandled cases                              |
| Use only `messageId` on `<Message>`                         | Add `messageDefault` attribute                     |
| Pass only needed Event.\* params                            | Pass entire BO through events                      |
| Return refresh flags from sub-processes                     | Force parent to always reload                      |

## Validation rules

The Process validator is the second-heaviest in the modeler — the dependency builder alone is 389 lines. Note the XSD quirk: the root element is `<Process>`, not `<ProcessFlow>`, even though the file extension and contract type use the ProcessFlow name.

### Cross-cutting (every contract)

-   Contract names must be unique workspace-wide — two Process files cannot share the same `@name`.
-   Files must be readable, well-formed XML with `<Process>` as the root element.

### Must

-   Root element is `<Process>` (not `<ProcessFlow>`).
-   File name ends with `.processflow.xml`. Custom Processes additionally start with the customizing indicator in the file name and the root `@name`.
-   Every `<Action @name>` must be unique within the Process; so must every `<Declaration>` and `<Input>` name in ProcessContext.
-   Every action reference resolves to an existing action: `defaultAction`, `<TransitionTo @action>`, `<DECISION><Case @action>`, `<VIEW><Events><Event @action>`, `<ExitHandler @transitionTo>`, and `<ExternalEvents><Event @action>` all get resolved by the dependency builder — a dangling name is rejected.
-   `<Declaration @type>` and `<Input @type>` must name an existing BO / LO / LU / UIDescription contract.
-   A `VIEW` action must declare exactly one `<UIDescription>` child (and at most one `<UIDescriptionLumina>`). The referenced UIDescription must exist.
-   For `DECISION` actions, the switch parameter must exist and at least one `<Case>` other than `CaseEmpty`/`CaseElse` should exist — single-case decisions are warned.
-   `<ExternalEventType @name>` must be one of `barcodeEvent`, `linkLaunchEvent`, `agentforceLaunchEvent`.
-   Action BO / LO / LU references must resolve, and `@process` attributes on sub-process calls must resolve.

### Must not

-   At most one `linkLaunchEvent` ExternalEvent per Process — duplicates are rejected.
-   Attributes that don't apply to the given `actionType` (e.g. LOGIC-only attrs on a LOAD action) are rejected.
-   Dropdown + paging LO bindings must have `paging="false"` on the LO — otherwise the dropdown pagination misbehaves (warned, not errored, but the runtime is broken).
-   `LOGIC` actions must not `call` a method from the deprecated engine-methods list — depending on the entry, deprecation is warned or rejected.

### Coerced (silently rewritten)

-   `actionType` values are case-normalized to their canonical enum — `load` becomes `LOAD`, `view` becomes `VIEW`, and so on. The migrator rewrites the file silently; there's no marker in the XML to tell you it happened.
-   `xmlns="*.xsd"` on the root is stripped.
-   `TransitionTo` pointing to the entry action is warned; missing `CaseEmpty`/`CaseElse` on a DECISION is warned / informational.

Internal schema reference: `rcg-mobile-dev-agent/wiki/contracts/process-flow.md`.

## Cross-References

-   [[business-objects]] — Process loads/saves/creates BOs
-   [[list-objects]] — Process loads LOs and passes to UI
-   [[user-interface]] — Process binds to UI via ProcessContext; events defined in UI
-   [[cockpit-cards]] — Cockpit uses complex lazy-load process patterns
-   [[business-logic]] — Process calls BL methods via LOGIC actions
