diff --git a/en/docs/api-reference/internal.md b/en/docs/api-reference/internal.md index edec082..9e288d7 100644 --- a/en/docs/api-reference/internal.md +++ b/en/docs/api-reference/internal.md @@ -53,7 +53,7 @@ virtual tables) there is a parallel surface in | `/treegrid/*` | `BusinessTreeGridController` | Tree-grid endpoints (the proc-backed path is implemented in this branch). | | `/procedureCall/*` | `GenericProcedureCallController` | Generic stored-procedure invocation by name + parameters — see [generic procedure dispatch](../reference/maintainer/proc-dispatch.md). | | `/panel/*` | `ConfigformPanelController` | Panel-layout persistence in `gdsconfigformpanel`. | -| `/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`. | +| `/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). | | `/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). | ## Reporting and printing diff --git a/en/docs/reference/maintainer/activiti.md b/en/docs/reference/maintainer/activiti.md index 3bb254c..1d3855a 100644 --- a/en/docs/reference/maintainer/activiti.md +++ b/en/docs/reference/maintainer/activiti.md @@ -1,106 +1,166 @@ # Activiti integration -> **Deferred for full coverage** — Activiti is wired into the codebase -> but cannot be observed end-to-end in a deployment that doesn't run -> approval flows. See [Slice 7 (deferred)](../../slices/07-workflow.md). +> **State on this dev DB: engine wired, never used.** The Activiti +> engine is fully bootstrapped at runtime, the `act_*` schema is +> provisioned, the BPMN modeler UI is reachable — but **every +> workflow-related table is empty**. No BPMN deployed, no process +> instances ever started, no `gdsmodule` row currently has +> `bCheck = 1`. The plumbing is hot; nothing is flowing. + +This page documents what's actually wired (concrete classes, URLs, +engine state) and what would have to be true for it to do anything. + +## Activiti is wired — engine ON + +Despite the dev DB being idle, the engine boots with `xlyEntry`: + +- `xlyFlow/build.gradle:15` pulls + `org.activiti:activiti-spring-boot-starter-rest-api:6.0.0`. That + starter transitively pulls `activiti-spring-boot-starter`, which + triggers Spring Boot's `ProcessEngineAutoConfiguration` to create + a `SpringProcessEngineConfiguration` bean. +- `xlyEntry/build.gradle` includes `xlyFlow` as `api project(':xlyFlow')`, + so the starter is on the runtime classpath of the `xlyEntry` WAR. +- `xlyEntry/.../EntryApplicationBoot.java:23-24` excludes only + `org.activiti.spring.boot.SecurityAutoConfiguration` (the + REST-endpoint security adapter) and Spring's own + `SecurityAutoConfiguration`. **Activiti's main engine + auto-config is NOT excluded** → the engine starts. +- `xlyFlow/.../activiti/config/ActivitiConfig.java` is a + `@Configuration implements ProcessEngineConfigurationConfigurer` + whose only job is to set Chinese-friendly fonts on the diagram + generator (`宋体` for activity / annotation / label fonts) and + install a custom `ICustomProcessDiagramGenerator`. +- `xlyApi`'s `ApiApplicationBoot` does NOT exclude Activiti either, + but xlyApi doesn't include xlyFlow as a dep, so xlyApi has the + engine's `org.activiti.engine.identity.User` class on classpath + (used only by `IdGen.java` for crypto utilities) but no Activiti + auto-config kicks in there. + +The 24 base `act_*` tables you see in the live schema are created by +the engine's auto-DDL on first boot. + +## Two Activiti versions on the classpath -This page captures what's *in the codebase* about Activiti so a future -maintainer doesn't start from zero when the workflow story is finally -exercised. +| Module | Version | Notes | +|---|---|---| +| `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. | +| `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. | -## Two Activiti versions +A maintainer cleaning up should drop `5.17.0` from `xlyPersist` and +`xlyApi`'s `build.gradle`. Verified: only `IdGen.java` in each of +those modules touches `org.activiti.engine.identity.User`, and the +type signature is satisfied by the 6.0 engine too — removal is safe. -The dependency tree carries **two** Activiti versions: +## What's actually invoked from code -| Module | Version | Notes | +The 154 Java files under `xlyFlow/src/main/java/com/xly/activiti/` +plus the modeler subpackage are real call sites. Selected anchors: + +| Activity | Class : line | Activiti API used | |---|---|---| -| `xlyPersist`, `xlyApi` | `org.activiti:activiti-engine:5.17.0` | Older 5.x line — declared in both modules | -| `xlyFlow` | `org.activiti:activiti-spring-boot-starter-rest-api:6.0.0`, `activiti-json-converter:6.0.0` | Newer 6.0 line | - -This is a real version mismatch. Activiti's 5.x and 6.x schemas overlap -but diverge in some `act_*` tables and migration paths. Possibilities: - -1. The framework runs Activiti 6.0 (xlyFlow drives the runtime) and - xlyPersist's 5.17 dependency is dead weight from an earlier era. -2. Different services use different versions for legacy reasons. -3. Both are in the classpath but only one is initialised at runtime. - -A future maintainer attacking this should: (a) remove the unused -version from both `xlyPersist` and `xlyApi` to avoid confusion, -(b) document which version the live schema uses, (c) verify the -`act_*` table layout matches that version exactly. - -One extra code fact matters in this branch: `xlyFlow/build.gradle` pulls -in the Activiti 6 starter, but `xlyFlow/src/main/java/com/xly/XlyFlowApplicationBoot.java` -is fully commented out. So workflow code is present, but this repository -does not currently present `xlyFlow` as a clearly runnable standalone app. - -## The `act_*` schema - -The framework ships the expected Activiti `act_*` schema — 24 base -tables (deployment, process-definition, runtime task, history etc.) -plus 3 *views* (`act_id_user`, `act_id_group`, `act_id_membership`). -The base tables populate only when a BPMN process is deployed and a -process instance is started. The identity views are notable: xly does -not maintain real Activiti identity tables; it projects its own -user/group schema into the `act_id_*` shapes via views, so Activiti -sees xly's logins as if they were native Activiti users. - -## xly's wrapper layer - -Three xly tables wrap the Activiti integration: - -- [`biz_flow`](../../auto-catalog/tables/biz_flow.md) — xly's per-document - flow state. -- [`biz_todo_item`](../../auto-catalog/tables/biz_todo_item.md) — - pending approver tasks. -- [`biz_todo_copyto`](../../auto-catalog/tables/biz_todo_copyto.md) — - CC'd parties on a flow. -- [`gdsmoduleflow`](../../auto-catalog/tables/gdsmoduleflow.md) + - `gdsmoduleflowslave` — module-flow window configuration. - -Like the underlying Activiti tables, these wrappers populate only in -deployments that actually run an approval flow. - -The pattern when active: a document submission writes a `biz_flow` -row + an Activiti process instance starts; pending approvers see -`biz_todo_item` rows; on approval the proc instance advances and -eventually completes. - -## Where Activiti is wired in code - -`xlyFlow/` is the dedicated module. Notable files (when this page is -fleshed out): - -- `xlyFlow`'s `pom`-equivalent gradle build pulls in Activiti 6.0. -- `xlyFlow/src/main/java/com/xly/activiti/config/ActivitiConfig.java` — - `@Configuration` implementing `ProcessEngineConfigurationConfigurer`, - the Spring Boot wire-up for Activiti's process engine. -- `CheckFlowController` in `xlyEntry/com/xly/web/businessweb/` is one - surface the SPA hits to drive workflow (approve / reject / view). - Note: the URL prefix is `/checkflow` (lowercase), not the camelCase - class name. -- `xlyFlow/src/main/java/com/xly/XlyFlowApplicationBoot.java` is fully - commented out on this branch — the workflow code is consumed as a - library through xlyEntry rather than as a standalone runnable. -- **No BPMN definitions ship in this repo** under - `xlyFlow/src/main/resources/` (no `processes/` subdir, no `*.bpmn*` - files). Deployments must supply them at runtime, e.g. via the - Activiti modeler whose static assets live at - `xlyFlow/src/main/resources/static/modeler/`. - -## What's needed to make Activiti work - -In a deployment that uses workflow: - -1. BPMN process definitions deployed (`act_re_procdef` populated). -2. Modules tagged `bCheck = 1` and linked to the right process via - `gdsmoduleflow`. -3. Approver users assigned via `act_id_*` or xly's wrapper of it. -4. The save endpoint, on `bCheck = 1` modules, branches to start a - process instance instead of (or alongside) the standard - add/update/delete. - -This page becomes a real reference once a deployment with deployed -processes is available; until then, treat it as an inventory of what -*ought* to be here. +| Start a process instance | `ProcessServiceImpl.submitApply()` :107 | `runtimeService.startProcessInstanceByKey(module, businessKey, variables)` | +| Complete a task | `CurrencyFlowController.complete(...)` :167 / `:200`; `WechatFlowPostThread` :132 | `processService.complete(taskId, ...)` → `taskService.complete()` | +| Query active tasks | `CurrencyFlowController` :409, :480 | `taskService.createTaskQuery().active().list()` | +| Query running instances | `CurrencyFlowController` :485, :659 | `runtimeService.createProcessInstanceQuery()` | +| Save a model in the modeler | `ModelerController.create()` :122 | `repositoryService.saveModel()` + `addModelEditorSource()` | +| Deploy a BPMN at runtime | `ModelerController.deploy()` :147 | `repositoryService.createDeployment().addString(name, bpmnXml).deploy()` | +| List process definitions | `ProcessDefinitionController` :135 | `repositoryService.createProcessDefinitionQuery()` | +| Read engine config | `ProcessActController` :281 | `ProcessEngines.getDefaultProcessEngine()` | +| 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 | + +## URLs the modeler exposes (xlyFlow controllers, on xlyEntry's port) + +Because xlyFlow is consumed as a library by xlyEntry (`api project(':xlyFlow')`), +all xlyFlow controllers compile into the xlyEntry WAR and serve at +xlyEntry's context-path (`/xlyEntry`). Notable URLs: + +- `POST /xlyEntry/modeler/model/{modelId}/save` — save BPMN-modeler XML +- `GET /xlyEntry/modeler/model/{modelId}/json` — load model for editor +- `GET /xlyEntry/modeler/editor/stencilset` — modeler stencil definitions +- `GET /xlyEntry/modeler/create` / `/modeler/deploy/{modelId}` — create + deploy +- `POST /xlyEntry/complete/{taskId}/{sBrandsId}/{sSubsidiaryId}/{sUserId}` — complete a task (CurrencyFlowController) +- `POST /xlyEntry/completeerp/{sBrandsId}/{sSubsidiaryId}/{sUserName}` — ERP-side completion variant + +These are not catalogued on the [Internal API page](../../api-reference/internal.md) +because they're rarely-touched workflow surface; treat the source as +authoritative. + +## What `CheckFlowController.java` actually contains + +This is a wiki-internal correction worth flagging: the class file +exists at `xlyEntry/src/main/java/com/xly/web/businessweb/CheckFlowController.java` +but its body is **22 lines, zero handler methods** — just a +`@RestController @RequestMapping(value="/checkflow")` shell with no +content. Earlier versions of this wiki described `/checkflow/*` as +"Activiti workflow surface (approve / reject / view)"; that is not +what the file currently contains. **`/checkflow/*` returns 404 for +any sub-path on the live system.** The actual approve/reject/view +URLs come from `CurrencyFlowController` and friends listed above. + +## The `act_*` schema state (this dev DB) + +| Table | Rows | Meaning when populated | +|---|---:|---| +| `act_re_model` | 0 | BPMN models saved in the modeler | +| `act_re_procdef` | 0 | Deployed process definitions | +| `act_ru_task` | 0 | Active (waiting) tasks | +| `act_hi_procinst` | 0 | Historical process instances | +| `act_id_user` / `act_id_group` / `act_id_membership` | (views) | Project xly's `sftlogininfo*` users into Activiti identity shape | +| `gdsmoduleflow` | 0 | xly's link from `gdsmodule` to a process definition | +| `biz_flow` | 0 | xly's per-document flow state | +| `biz_todo_item` | 0 | Pending approver tasks (xly wrapper, not Activiti's `act_ru_task`) | +| `biz_todo_copyto` | 0 | CC'd parties on a flow | + +So Activiti is **stone-cold idle**. Engine running, schemas ready, no traffic. + +## What would make it move + +For a flow to actually run, in roughly this order: + +1. An engineer or PM opens the **modeler UI** (modeler static assets at + `xlyFlow/src/main/resources/static/modeler/`, served via the + `/modeler/*` endpoints). They draw a BPMN, save it + (`act_re_model` populated). +2. They click *Deploy* in the modeler → + `ModelerController.deploy()` calls + `repositoryService.createDeployment().addString(name, bpmnXml).deploy()` + → `act_re_procdef` populated. +3. A `gdsmodule` row is tagged `bCheck = 1` and a row in + `gdsmoduleflow` links the module to the deployed + `act_re_procdef.KEY_`. +4. When a user saves a row on that module, the save service detects + `bCheck = 1` and calls `ProcessServiceImpl.submitApply(applyUserId, businessKey, itemName, itemContent, module, variables)`. + That fires `runtimeService.startProcessInstanceByKey(module, businessKey, variables)` + → `act_ru_*` tables populate, `biz_flow` + `biz_todo_item` get xly-side rows. +5. Approvers see pending tasks in their FROUNT inbox (probably the + "审批" tab, separate from KPI Work Center). They click 通过/驳回 → + `CurrencyFlowController.complete()` → `taskService.complete()`. +6. When the proc instance reaches `endEvent`, the row's `bCheck` + transitions; downstream queries that filter on `bCheck = 1` start + seeing it. + +## Why xly bothered with Activiti at all + +The codebase has its own `biz_flow` / `biz_todo_item` tables that +*could* implement a hand-rolled approval system. The decision to put +Activiti behind them buys: + +- Standard BPMN modeling (the JS modeler pulls the same stencilset as + Activiti Explorer). +- Free state-machine semantics — the engine handles "task A done → + task B available" without xly maintaining the FSM in SQL. +- Diagram rendering (the page-as-PNG in `ProcessActController`). + +The cost: a second engine running in the JVM, a second DB schema with +its own DDL drift, a second authentication surface (which xly papers +over via the `act_id_*` views). + +## What this page is *not* + +- A Slice 7 substitute. Slice 7 (deferred) would document an + end-to-end traced flow against a deployment that actually runs one. +- A modeler tutorial. The modeler comes from the Activiti project; xly + embeds it as static assets without modification. +- A migration plan from Activiti to anything else. That would be a + larger architectural decision, not a wiki finding. diff --git a/en/docs/reference/maintainer/runtime.md b/en/docs/reference/maintainer/runtime.md index a73246a..1e5146e 100644 --- a/en/docs/reference/maintainer/runtime.md +++ b/en/docs/reference/maintainer/runtime.md @@ -16,7 +16,7 @@ controllers and services that carry most of the generic form runtime. | `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}` | | `GenericProcedureCallController` | `web/businessweb/` | Generic stored-procedure invocation by name + parameters. | `/procedureCall/doGenericProcedureCall` | | `ConfigformPanelController` | `web/businessweb/` | Panel-layout persistence in `gdsconfigformpanel`. | `/panel/get/{sFormId}`, `/panel/save/{sFormId}` | -| `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) | +| `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) | | `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` | Note that the controllers split across **two packages**: `businessweb/`