Commit 96573a81f48ee0190d3ee4aa682ef8fb9d5886c0
1 parent
e5d5c98e
docs: en wiki — Activiti is wired but idle, not "deferred"
Re-investigated Activiti's actual integration after the user asked
how it's used. Substantive findings:
State on this dev DB: engine wired, never used.
- The Activiti 6.0 engine bootstraps with xlyEntry. activiti-spring-
boot-starter-rest-api:6.0.0 declared in xlyFlow/build.gradle pulls
ProcessEngineAutoConfiguration. xlyEntry's
EntryApplicationBoot only excludes Activiti's
REST-security autoconfig, not the engine. xlyFlow is consumed as
api project(':xlyFlow') in xlyEntry, so all xlyFlow controllers
serve at xlyEntry's context-path.
- ActivitiConfig.java is a real @Configuration that wires Chinese
fonts and a custom ICustomProcessDiagramGenerator into the engine.
- Real call sites confirmed:
* runtimeService.startProcessInstanceByKey(...) at
ProcessServiceImpl.java:107
* taskService / repositoryService used across CurrencyFlowController,
ModelerController, ProcessDefinitionController,
ProcessActController, BizTodoItemServiceImpl, etc.
* Modeler endpoints: /modeler/model/{id}/save, /modeler/editor/
stencilset, /modeler/create, /modeler/deploy/{id}.
- Empirical state: every workflow table is 0 rows in this dev DB —
act_re_model, act_re_procdef, act_ru_task, act_hi_procinst,
gdsmoduleflow, biz_flow, biz_todo_item, plus 0 gdsmodule rows
with bCheck=1. Engine running, plumbing hot, no traffic.
CheckFlowController correction:
- The class file is 22 lines with ZERO handler methods. Just
@RestController @RequestMapping("/checkflow") shell. The wiki
previously described it as "Activiti workflow surface (approve/
reject/view)" — this was wrong. /checkflow/* returns 404.
- Real workflow URLs live in xlyFlow's CurrencyFlowController:
/complete/{taskId}/{sBrandsId}/{sSubsidiaryId}/{sUserId},
/completeerp/{...}, plus /modeler/* for BPMN authoring.
- Fixed in runtime.md (load-bearing-controllers row),
internal.md (specialised-runtime row), with cross-link to
activiti.md.
activiti.md rewritten:
- Reframed from "deferred for full coverage" to "engine wired,
never used in this dev DB" — the engine state is concrete and
documentable; only the flow content is empty.
- Added "Activiti is wired — engine ON" section with the
bootstrap chain.
- Added a concrete table of Activiti API call sites (file:line
+ which Activiti service is invoked).
- Added URLs-the-modeler-exposes section listing the real
workflow URLs served via xlyEntry.
- Added the act_* schema state table with the live 0-row counts.
- Added "What would make it move" — the 6-step path from drawing
a BPMN to seeing a flowing approval.
- Added "Why xly bothered with Activiti at all" — the
architectural rationale.
- Documented xlyApi/xlyPersist 5.17 declarations as vestigial
(only IdGen.java's User import; type signature works under 6.0
too — safe to remove).
Showing
3 changed files
with
161 additions
and
101 deletions
en/docs/api-reference/internal.md
| ... | ... | @@ -53,7 +53,7 @@ virtual tables) there is a parallel surface in |
| 53 | 53 | | `/treegrid/*` | `BusinessTreeGridController` | Tree-grid endpoints (the proc-backed path is implemented in this branch). | |
| 54 | 54 | | `/procedureCall/*` | `GenericProcedureCallController` | Generic stored-procedure invocation by name + parameters — see [generic procedure dispatch](../reference/maintainer/proc-dispatch.md). | |
| 55 | 55 | | `/panel/*` | `ConfigformPanelController` | Panel-layout persistence in `gdsconfigformpanel`. | |
| 56 | -| `/checkflow/*` | `CheckFlowController` | Activiti workflow surface (approve / reject / view) — only meaningful in deployments that run a flow. The class file is `CheckFlowController.java` (camelCase) but the `@RequestMapping` value is all-lowercase `/checkflow`. | | |
| 56 | +| `/checkflow/*` | `CheckFlowController` | **Empty shell — returns 404.** The class declares the prefix but has zero handler methods. The actual workflow approve/reject/complete URLs come from xlyFlow's `CurrencyFlowController` (served at xlyEntry's context-path because xlyFlow is a library dep): `/complete/{taskId}/{sBrandsId}/{sSubsidiaryId}/{sUserId}`, `/completeerp/...`, plus `/modeler/*` for the BPMN modeler. See [Activiti integration](../reference/maintainer/activiti.md). | | |
| 57 | 57 | | `/modelCenter/getModelCenter`, `/modelCenter/getModelCenterCalculation` | `BusinessModelCenterController` | The FROUNT home-page **KPI Work Center** card (titled `KPI监控`). Aggregates open tasks across modules tagged `gdsmodule.bUnTask=1`, partitioned by role and business flow. **Not Activiti-driven.** See [The KPI Work Center](../reference/maintainer/runtime.md#the-kpi-work-center-front-end-home-dashboard). | |
| 58 | 58 | |
| 59 | 59 | ## Reporting and printing | ... | ... |
en/docs/reference/maintainer/activiti.md
| 1 | 1 | # Activiti integration |
| 2 | 2 | |
| 3 | -> **Deferred for full coverage** — Activiti is wired into the codebase | |
| 4 | -> but cannot be observed end-to-end in a deployment that doesn't run | |
| 5 | -> approval flows. See [Slice 7 (deferred)](../../slices/07-workflow.md). | |
| 3 | +> **State on this dev DB: engine wired, never used.** The Activiti | |
| 4 | +> engine is fully bootstrapped at runtime, the `act_*` schema is | |
| 5 | +> provisioned, the BPMN modeler UI is reachable — but **every | |
| 6 | +> workflow-related table is empty**. No BPMN deployed, no process | |
| 7 | +> instances ever started, no `gdsmodule` row currently has | |
| 8 | +> `bCheck = 1`. The plumbing is hot; nothing is flowing. | |
| 9 | + | |
| 10 | +This page documents what's actually wired (concrete classes, URLs, | |
| 11 | +engine state) and what would have to be true for it to do anything. | |
| 12 | + | |
| 13 | +## Activiti is wired — engine ON | |
| 14 | + | |
| 15 | +Despite the dev DB being idle, the engine boots with `xlyEntry`: | |
| 16 | + | |
| 17 | +- `xlyFlow/build.gradle:15` pulls | |
| 18 | + `org.activiti:activiti-spring-boot-starter-rest-api:6.0.0`. That | |
| 19 | + starter transitively pulls `activiti-spring-boot-starter`, which | |
| 20 | + triggers Spring Boot's `ProcessEngineAutoConfiguration` to create | |
| 21 | + a `SpringProcessEngineConfiguration` bean. | |
| 22 | +- `xlyEntry/build.gradle` includes `xlyFlow` as `api project(':xlyFlow')`, | |
| 23 | + so the starter is on the runtime classpath of the `xlyEntry` WAR. | |
| 24 | +- `xlyEntry/.../EntryApplicationBoot.java:23-24` excludes only | |
| 25 | + `org.activiti.spring.boot.SecurityAutoConfiguration` (the | |
| 26 | + REST-endpoint security adapter) and Spring's own | |
| 27 | + `SecurityAutoConfiguration`. **Activiti's main engine | |
| 28 | + auto-config is NOT excluded** → the engine starts. | |
| 29 | +- `xlyFlow/.../activiti/config/ActivitiConfig.java` is a | |
| 30 | + `@Configuration implements ProcessEngineConfigurationConfigurer` | |
| 31 | + whose only job is to set Chinese-friendly fonts on the diagram | |
| 32 | + generator (`宋体` for activity / annotation / label fonts) and | |
| 33 | + install a custom `ICustomProcessDiagramGenerator`. | |
| 34 | +- `xlyApi`'s `ApiApplicationBoot` does NOT exclude Activiti either, | |
| 35 | + but xlyApi doesn't include xlyFlow as a dep, so xlyApi has the | |
| 36 | + engine's `org.activiti.engine.identity.User` class on classpath | |
| 37 | + (used only by `IdGen.java` for crypto utilities) but no Activiti | |
| 38 | + auto-config kicks in there. | |
| 39 | + | |
| 40 | +The 24 base `act_*` tables you see in the live schema are created by | |
| 41 | +the engine's auto-DDL on first boot. | |
| 42 | + | |
| 43 | +## Two Activiti versions on the classpath | |
| 6 | 44 | |
| 7 | -This page captures what's *in the codebase* about Activiti so a future | |
| 8 | -maintainer doesn't start from zero when the workflow story is finally | |
| 9 | -exercised. | |
| 45 | +| Module | Version | Notes | | |
| 46 | +|---|---|---| | |
| 47 | +| `xlyPersist`, `xlyApi` | `org.activiti:activiti-engine:5.17.0` | Older 5.x line — declared in both modules. **Vestigial** — the runtime engine in `xlyEntry`'s WAR is the 6.0 one pulled by xlyFlow's starter. The 5.17 declarations are dead weight on the classpath. | | |
| 48 | +| `xlyFlow` | `org.activiti:activiti-spring-boot-starter-rest-api:6.0.0`, `activiti-json-converter:6.0.0` | Newer 6.0 line — this is what runs. | | |
| 10 | 49 | |
| 11 | -## Two Activiti versions | |
| 50 | +A maintainer cleaning up should drop `5.17.0` from `xlyPersist` and | |
| 51 | +`xlyApi`'s `build.gradle`. Verified: only `IdGen.java` in each of | |
| 52 | +those modules touches `org.activiti.engine.identity.User`, and the | |
| 53 | +type signature is satisfied by the 6.0 engine too — removal is safe. | |
| 12 | 54 | |
| 13 | -The dependency tree carries **two** Activiti versions: | |
| 55 | +## What's actually invoked from code | |
| 14 | 56 | |
| 15 | -| Module | Version | Notes | | |
| 57 | +The 154 Java files under `xlyFlow/src/main/java/com/xly/activiti/` | |
| 58 | +plus the modeler subpackage are real call sites. Selected anchors: | |
| 59 | + | |
| 60 | +| Activity | Class : line | Activiti API used | | |
| 16 | 61 | |---|---|---| |
| 17 | -| `xlyPersist`, `xlyApi` | `org.activiti:activiti-engine:5.17.0` | Older 5.x line — declared in both modules | | |
| 18 | -| `xlyFlow` | `org.activiti:activiti-spring-boot-starter-rest-api:6.0.0`, `activiti-json-converter:6.0.0` | Newer 6.0 line | | |
| 19 | - | |
| 20 | -This is a real version mismatch. Activiti's 5.x and 6.x schemas overlap | |
| 21 | -but diverge in some `act_*` tables and migration paths. Possibilities: | |
| 22 | - | |
| 23 | -1. The framework runs Activiti 6.0 (xlyFlow drives the runtime) and | |
| 24 | - xlyPersist's 5.17 dependency is dead weight from an earlier era. | |
| 25 | -2. Different services use different versions for legacy reasons. | |
| 26 | -3. Both are in the classpath but only one is initialised at runtime. | |
| 27 | - | |
| 28 | -A future maintainer attacking this should: (a) remove the unused | |
| 29 | -version from both `xlyPersist` and `xlyApi` to avoid confusion, | |
| 30 | -(b) document which version the live schema uses, (c) verify the | |
| 31 | -`act_*` table layout matches that version exactly. | |
| 32 | - | |
| 33 | -One extra code fact matters in this branch: `xlyFlow/build.gradle` pulls | |
| 34 | -in the Activiti 6 starter, but `xlyFlow/src/main/java/com/xly/XlyFlowApplicationBoot.java` | |
| 35 | -is fully commented out. So workflow code is present, but this repository | |
| 36 | -does not currently present `xlyFlow` as a clearly runnable standalone app. | |
| 37 | - | |
| 38 | -## The `act_*` schema | |
| 39 | - | |
| 40 | -The framework ships the expected Activiti `act_*` schema — 24 base | |
| 41 | -tables (deployment, process-definition, runtime task, history etc.) | |
| 42 | -plus 3 *views* (`act_id_user`, `act_id_group`, `act_id_membership`). | |
| 43 | -The base tables populate only when a BPMN process is deployed and a | |
| 44 | -process instance is started. The identity views are notable: xly does | |
| 45 | -not maintain real Activiti identity tables; it projects its own | |
| 46 | -user/group schema into the `act_id_*` shapes via views, so Activiti | |
| 47 | -sees xly's logins as if they were native Activiti users. | |
| 48 | - | |
| 49 | -## xly's wrapper layer | |
| 50 | - | |
| 51 | -Three xly tables wrap the Activiti integration: | |
| 52 | - | |
| 53 | -- [`biz_flow`](../../auto-catalog/tables/biz_flow.md) — xly's per-document | |
| 54 | - flow state. | |
| 55 | -- [`biz_todo_item`](../../auto-catalog/tables/biz_todo_item.md) — | |
| 56 | - pending approver tasks. | |
| 57 | -- [`biz_todo_copyto`](../../auto-catalog/tables/biz_todo_copyto.md) — | |
| 58 | - CC'd parties on a flow. | |
| 59 | -- [`gdsmoduleflow`](../../auto-catalog/tables/gdsmoduleflow.md) + | |
| 60 | - `gdsmoduleflowslave` — module-flow window configuration. | |
| 61 | - | |
| 62 | -Like the underlying Activiti tables, these wrappers populate only in | |
| 63 | -deployments that actually run an approval flow. | |
| 64 | - | |
| 65 | -The pattern when active: a document submission writes a `biz_flow` | |
| 66 | -row + an Activiti process instance starts; pending approvers see | |
| 67 | -`biz_todo_item` rows; on approval the proc instance advances and | |
| 68 | -eventually completes. | |
| 69 | - | |
| 70 | -## Where Activiti is wired in code | |
| 71 | - | |
| 72 | -`xlyFlow/` is the dedicated module. Notable files (when this page is | |
| 73 | -fleshed out): | |
| 74 | - | |
| 75 | -- `xlyFlow`'s `pom`-equivalent gradle build pulls in Activiti 6.0. | |
| 76 | -- `xlyFlow/src/main/java/com/xly/activiti/config/ActivitiConfig.java` — | |
| 77 | - `@Configuration` implementing `ProcessEngineConfigurationConfigurer`, | |
| 78 | - the Spring Boot wire-up for Activiti's process engine. | |
| 79 | -- `CheckFlowController` in `xlyEntry/com/xly/web/businessweb/` is one | |
| 80 | - surface the SPA hits to drive workflow (approve / reject / view). | |
| 81 | - Note: the URL prefix is `/checkflow` (lowercase), not the camelCase | |
| 82 | - class name. | |
| 83 | -- `xlyFlow/src/main/java/com/xly/XlyFlowApplicationBoot.java` is fully | |
| 84 | - commented out on this branch — the workflow code is consumed as a | |
| 85 | - library through xlyEntry rather than as a standalone runnable. | |
| 86 | -- **No BPMN definitions ship in this repo** under | |
| 87 | - `xlyFlow/src/main/resources/` (no `processes/` subdir, no `*.bpmn*` | |
| 88 | - files). Deployments must supply them at runtime, e.g. via the | |
| 89 | - Activiti modeler whose static assets live at | |
| 90 | - `xlyFlow/src/main/resources/static/modeler/`. | |
| 91 | - | |
| 92 | -## What's needed to make Activiti work | |
| 93 | - | |
| 94 | -In a deployment that uses workflow: | |
| 95 | - | |
| 96 | -1. BPMN process definitions deployed (`act_re_procdef` populated). | |
| 97 | -2. Modules tagged `bCheck = 1` and linked to the right process via | |
| 98 | - `gdsmoduleflow`. | |
| 99 | -3. Approver users assigned via `act_id_*` or xly's wrapper of it. | |
| 100 | -4. The save endpoint, on `bCheck = 1` modules, branches to start a | |
| 101 | - process instance instead of (or alongside) the standard | |
| 102 | - add/update/delete. | |
| 103 | - | |
| 104 | -This page becomes a real reference once a deployment with deployed | |
| 105 | -processes is available; until then, treat it as an inventory of what | |
| 106 | -*ought* to be here. | |
| 62 | +| Start a process instance | `ProcessServiceImpl.submitApply()` :107 | `runtimeService.startProcessInstanceByKey(module, businessKey, variables)` | | |
| 63 | +| Complete a task | `CurrencyFlowController.complete(...)` :167 / `:200`; `WechatFlowPostThread` :132 | `processService.complete(taskId, ...)` → `taskService.complete()` | | |
| 64 | +| Query active tasks | `CurrencyFlowController` :409, :480 | `taskService.createTaskQuery().active().list()` | | |
| 65 | +| Query running instances | `CurrencyFlowController` :485, :659 | `runtimeService.createProcessInstanceQuery()` | | |
| 66 | +| Save a model in the modeler | `ModelerController.create()` :122 | `repositoryService.saveModel()` + `addModelEditorSource()` | | |
| 67 | +| Deploy a BPMN at runtime | `ModelerController.deploy()` :147 | `repositoryService.createDeployment().addString(name, bpmnXml).deploy()` | | |
| 68 | +| List process definitions | `ProcessDefinitionController` :135 | `repositoryService.createProcessDefinitionQuery()` | | |
| 69 | +| Read engine config | `ProcessActController` :281 | `ProcessEngines.getDefaultProcessEngine()` | | |
| 70 | +| Bridge xly users into Activiti identity | `act_id_user` / `act_id_group` / `act_id_membership` are **views** projecting xly's `sftlogininfo*` schema | xly does not write to Activiti's identity tables; the views fake them | | |
| 71 | + | |
| 72 | +## URLs the modeler exposes (xlyFlow controllers, on xlyEntry's port) | |
| 73 | + | |
| 74 | +Because xlyFlow is consumed as a library by xlyEntry (`api project(':xlyFlow')`), | |
| 75 | +all xlyFlow controllers compile into the xlyEntry WAR and serve at | |
| 76 | +xlyEntry's context-path (`/xlyEntry`). Notable URLs: | |
| 77 | + | |
| 78 | +- `POST /xlyEntry/modeler/model/{modelId}/save` — save BPMN-modeler XML | |
| 79 | +- `GET /xlyEntry/modeler/model/{modelId}/json` — load model for editor | |
| 80 | +- `GET /xlyEntry/modeler/editor/stencilset` — modeler stencil definitions | |
| 81 | +- `GET /xlyEntry/modeler/create` / `/modeler/deploy/{modelId}` — create + deploy | |
| 82 | +- `POST /xlyEntry/complete/{taskId}/{sBrandsId}/{sSubsidiaryId}/{sUserId}` — complete a task (CurrencyFlowController) | |
| 83 | +- `POST /xlyEntry/completeerp/{sBrandsId}/{sSubsidiaryId}/{sUserName}` — ERP-side completion variant | |
| 84 | + | |
| 85 | +These are not catalogued on the [Internal API page](../../api-reference/internal.md) | |
| 86 | +because they're rarely-touched workflow surface; treat the source as | |
| 87 | +authoritative. | |
| 88 | + | |
| 89 | +## What `CheckFlowController.java` actually contains | |
| 90 | + | |
| 91 | +This is a wiki-internal correction worth flagging: the class file | |
| 92 | +exists at `xlyEntry/src/main/java/com/xly/web/businessweb/CheckFlowController.java` | |
| 93 | +but its body is **22 lines, zero handler methods** — just a | |
| 94 | +`@RestController @RequestMapping(value="/checkflow")` shell with no | |
| 95 | +content. Earlier versions of this wiki described `/checkflow/*` as | |
| 96 | +"Activiti workflow surface (approve / reject / view)"; that is not | |
| 97 | +what the file currently contains. **`/checkflow/*` returns 404 for | |
| 98 | +any sub-path on the live system.** The actual approve/reject/view | |
| 99 | +URLs come from `CurrencyFlowController` and friends listed above. | |
| 100 | + | |
| 101 | +## The `act_*` schema state (this dev DB) | |
| 102 | + | |
| 103 | +| Table | Rows | Meaning when populated | | |
| 104 | +|---|---:|---| | |
| 105 | +| `act_re_model` | 0 | BPMN models saved in the modeler | | |
| 106 | +| `act_re_procdef` | 0 | Deployed process definitions | | |
| 107 | +| `act_ru_task` | 0 | Active (waiting) tasks | | |
| 108 | +| `act_hi_procinst` | 0 | Historical process instances | | |
| 109 | +| `act_id_user` / `act_id_group` / `act_id_membership` | (views) | Project xly's `sftlogininfo*` users into Activiti identity shape | | |
| 110 | +| `gdsmoduleflow` | 0 | xly's link from `gdsmodule` to a process definition | | |
| 111 | +| `biz_flow` | 0 | xly's per-document flow state | | |
| 112 | +| `biz_todo_item` | 0 | Pending approver tasks (xly wrapper, not Activiti's `act_ru_task`) | | |
| 113 | +| `biz_todo_copyto` | 0 | CC'd parties on a flow | | |
| 114 | + | |
| 115 | +So Activiti is **stone-cold idle**. Engine running, schemas ready, no traffic. | |
| 116 | + | |
| 117 | +## What would make it move | |
| 118 | + | |
| 119 | +For a flow to actually run, in roughly this order: | |
| 120 | + | |
| 121 | +1. An engineer or PM opens the **modeler UI** (modeler static assets at | |
| 122 | + `xlyFlow/src/main/resources/static/modeler/`, served via the | |
| 123 | + `/modeler/*` endpoints). They draw a BPMN, save it | |
| 124 | + (`act_re_model` populated). | |
| 125 | +2. They click *Deploy* in the modeler → | |
| 126 | + `ModelerController.deploy()` calls | |
| 127 | + `repositoryService.createDeployment().addString(name, bpmnXml).deploy()` | |
| 128 | + → `act_re_procdef` populated. | |
| 129 | +3. A `gdsmodule` row is tagged `bCheck = 1` and a row in | |
| 130 | + `gdsmoduleflow` links the module to the deployed | |
| 131 | + `act_re_procdef.KEY_`. | |
| 132 | +4. When a user saves a row on that module, the save service detects | |
| 133 | + `bCheck = 1` and calls `ProcessServiceImpl.submitApply(applyUserId, businessKey, itemName, itemContent, module, variables)`. | |
| 134 | + That fires `runtimeService.startProcessInstanceByKey(module, businessKey, variables)` | |
| 135 | + → `act_ru_*` tables populate, `biz_flow` + `biz_todo_item` get xly-side rows. | |
| 136 | +5. Approvers see pending tasks in their FROUNT inbox (probably the | |
| 137 | + "审批" tab, separate from KPI Work Center). They click 通过/驳回 → | |
| 138 | + `CurrencyFlowController.complete()` → `taskService.complete()`. | |
| 139 | +6. When the proc instance reaches `endEvent`, the row's `bCheck` | |
| 140 | + transitions; downstream queries that filter on `bCheck = 1` start | |
| 141 | + seeing it. | |
| 142 | + | |
| 143 | +## Why xly bothered with Activiti at all | |
| 144 | + | |
| 145 | +The codebase has its own `biz_flow` / `biz_todo_item` tables that | |
| 146 | +*could* implement a hand-rolled approval system. The decision to put | |
| 147 | +Activiti behind them buys: | |
| 148 | + | |
| 149 | +- Standard BPMN modeling (the JS modeler pulls the same stencilset as | |
| 150 | + Activiti Explorer). | |
| 151 | +- Free state-machine semantics — the engine handles "task A done → | |
| 152 | + task B available" without xly maintaining the FSM in SQL. | |
| 153 | +- Diagram rendering (the page-as-PNG in `ProcessActController`). | |
| 154 | + | |
| 155 | +The cost: a second engine running in the JVM, a second DB schema with | |
| 156 | +its own DDL drift, a second authentication surface (which xly papers | |
| 157 | +over via the `act_id_*` views). | |
| 158 | + | |
| 159 | +## What this page is *not* | |
| 160 | + | |
| 161 | +- A Slice 7 substitute. Slice 7 (deferred) would document an | |
| 162 | + end-to-end traced flow against a deployment that actually runs one. | |
| 163 | +- A modeler tutorial. The modeler comes from the Activiti project; xly | |
| 164 | + embeds it as static assets without modification. | |
| 165 | +- A migration plan from Activiti to anything else. That would be a | |
| 166 | + larger architectural decision, not a wiki finding. | ... | ... |
en/docs/reference/maintainer/runtime.md
| ... | ... | @@ -16,7 +16,7 @@ controllers and services that carry most of the generic form runtime. |
| 16 | 16 | | `BusinessTreeGridController` | `web/businessweb/` | Tree-grid endpoints. In this branch, the proc-backed path is implemented; the plain `getTreeGrid` service method is still a stub. | `/treegrid/getTreeGridByPro/{formId}` | |
| 17 | 17 | | `GenericProcedureCallController` | `web/businessweb/` | Generic stored-procedure invocation by name + parameters. | `/procedureCall/doGenericProcedureCall` | |
| 18 | 18 | | `ConfigformPanelController` | `web/businessweb/` | Panel-layout persistence in `gdsconfigformpanel`. | `/panel/get/{sFormId}`, `/panel/save/{sFormId}` | |
| 19 | -| `CheckFlowController` | `web/businessweb/` | Activiti workflow surface (approve / reject / view) — only meaningful when workflow is deployed. | endpoints under `/checkflow/*` (the class file is `CheckFlowController.java` in camelCase but the `@RequestMapping` value is all-lowercase) | | |
| 19 | +| `CheckFlowController` | `web/businessweb/` | **Empty shell.** The class file is 22 lines: just a `@RestController @RequestMapping(value="/checkflow")` with no handler methods. `/checkflow/*` returns 404. The actual workflow approve/reject/complete URLs live in `CurrencyFlowController` (in `xlyFlow`, served via xlyEntry's context-path) — see [Activiti integration](activiti.md#urls-the-modeler-exposes-xlyflow-controllers-on-xlyentrys-port). | (none — empty class) | | |
| 20 | 20 | | `BusinessModelCenterController` | `web/businessweb/` | The "KPI Work Center" home dashboard on FROUNT — open-task aggregation across modules tagged with `gdsmodule.bUnTask=1`. **Not Activiti-driven** despite the workflow-flavoured UI; reads from `gdsmodule` rows partitioned by `sUnType` ∈ {`Pending`, `PendingCheck`, `MyWarning`}. Cached per user. See [The KPI Work Center](#the-kpi-work-center-front-end-home-dashboard) below. | `/modelCenter/getModelCenter`, `/modelCenter/getModelCenterCalculation` | |
| 21 | 21 | |
| 22 | 22 | Note that the controllers split across **two packages**: `businessweb/` | ... | ... |