Commit 96573a81f48ee0190d3ee4aa682ef8fb9d5886c0

Authored by zichun
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).
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/`
... ...