diff --git a/en/docs/concepts/customization-channels.md b/en/docs/concepts/customization-channels.md index d194667..9ce50b5 100644 --- a/en/docs/concepts/customization-channels.md +++ b/en/docs/concepts/customization-channels.md @@ -63,8 +63,10 @@ Use **Channel 2** when: procs don't express. - You need to replace a stored procedure body, not just inject SQL fragments around it. -- A maintainer reviewing the customer's runtime would benefit from - seeing the difference in source-controlled SQL files. +- The runtime divergence should live in source-controlled `.sql` + files (under `script/客户//`) so a maintainer reviewing + the customer's runtime can see the per-customer changes at a glance, + rather than discovering them only by connecting to the live DB. Channel 2 is *almost always a last resort*. Reach for it only after confirming Channel 1 cannot do the job. diff --git a/en/docs/reference/builder/attach-workflow.md b/en/docs/reference/builder/attach-workflow.md index 92b0213..8e5a5d9 100644 --- a/en/docs/reference/builder/attach-workflow.md +++ b/en/docs/reference/builder/attach-workflow.md @@ -1,5 +1,14 @@ # How to attach a workflow +> **Deferred — needs a deployment with deployed BPMN.** Empirically +> confirmed against the dev DB: `SELECT COUNT(*) FROM act_re_procdef` +> returns 0; `gdsmoduleflow = 0`; `gdsmodule WHERE bCheck = 1` matches +> 0 rows. The dispatch path itself is hard-disabled by +> `ConstantUtils.bCheckflowCheck = false` (see +> [Activiti integration](../../reference/maintainer/activiti.md)). The +> recipe below is the **code-derived hypothesis** — it has not been +> exercised against a live deployment. + > **Deferred.** Activiti is wired into the codebase, but a deployment > that doesn't run an approval flow leaves the workflow tables empty, > so end-to-end verification of this recipe needs a deployment that diff --git a/en/docs/reference/builder/define-vtable.md b/en/docs/reference/builder/define-vtable.md index c009e54..2b943bf 100644 --- a/en/docs/reference/builder/define-vtable.md +++ b/en/docs/reference/builder/define-vtable.md @@ -31,27 +31,50 @@ One row per virtual table: | Column | Value | |---|---| | `sId` | unique virtual-table ID | -| `sName` | the virtual-table's logical name | | `sChinese` / `sEnglish` / `sBig5` | display name | | `sBrandsId` / `sSubsidiaryId` | tenant scope | -| `sTbName` | the underlying physical table name (if backed by one) | -| (other configuration columns describing storage and indexing) | +| `sTbName` | the underlying physical name. **In practice this points at a table, view, *or* stored procedure** — the column is unique-keyed but otherwise unconstrained. The runtime resolves it as a generic SQL identifier. | +| `sParentId` | parent virtual table for tree-style classifications (empty for flat tables) | +| `iOrder` | sort order in the BACK list | ### 2. The columns — `gdsconfigtbslave` One row per column. Each row carries the column's name, type, default, display label, validation, and whether it's part of the primary key. -## Open: what backs the data +## What `sTbName` actually points at — and the drift -Every `gdsconfigtbmaster` row carries a non-empty `sTbName`, but in -practice some of those names may not resolve to a current object in -`information_schema.tables` — schema migrations and renames happen -faster than the metadata is cleaned up. So the safe statement is: the -metadata *expects* an underlying SQL object, but a deployed schema is -not always perfectly aligned for every virtual-table row. An audit -script that diffs `gdsconfigtbmaster.sTbName` against -`information_schema.tables` is the cleanest way to surface drift. +Every `gdsconfigtbmaster` row carries a non-empty `sTbName`, but the +column is just a unique-keyed string — the framework doesn't enforce +that it resolves to a base table. Verified against the live dev DB: + +- 307 `gdsconfigtbmaster` rows total. +- **296 (96.4 %) resolve to a real `BASE TABLE`** in + `information_schema.tables`. +- **11 (3.6 %) do not resolve** — and the breakdown is itself + informative: + + | Where the unresolved `sTbName` actually points | Count | Examples | + |---|---:|---| + | A view (`viw_*`) instead of a table | 4 | `viw_mftproductionreport`, `viw_mftproductionreportEmployee1` | + | A stored procedure (`Sp_*`) | 3 | `Sp_Cashier_BankJournal`, `Sp_Cashier_SumJournal`, `Sp_Sales_NotDeliverGoodNotifyList` | + | A real table that exists under a different case-folded name, or a renamed/dropped object | 4 | `QlyProcessTestResult` (case drift), … | + +So `sTbName` is **not** strictly "the physical table name" — it is the +generic SQL identifier the runtime will substitute into the read query, +which can equally point at a view or a callable proc. The wiki's +earlier framing ("the underlying physical table name") was too narrow. + +Audit pattern that surfaces drift: + +```sql +SELECT sId, sChinese, sTbName +FROM gdsconfigtbmaster +WHERE sTbName NOT IN ( + SELECT TABLE_NAME FROM information_schema.tables + WHERE TABLE_SCHEMA = DATABASE() +); +``` ## When to choose virtual table vs. view vs. table @@ -65,9 +88,41 @@ The virtual-table channel is the framework's "type system" for data-driven shapes; the physical schema is what actually stores rows. The two are deliberately decoupled. -## Worked example +## Worked example — `包装方式` (Packing-method lookup) -This page would benefit from a concrete worked example — pick a real -virtual table from `gdsconfigtbmaster` and walk through its master row + -slave rows. A future revision -of the wiki should add this. +A representative real row from the dev DB: + +**Master** (`gdsconfigtbmaster`): + +``` +sId = 192116810113315231587698560 +sChinese = 包装方式 (Packing method) +sTbName = SisPacking +sParentId = (root) +``` + +**Slave columns** (`gdsconfigtbslave`, 10 rows under that `sParentId`) +declare the *logical* shape — names, display labels, validation. The +*physical* shape lives in the real `SisPacking` table: + +| Slave row | Backing physical column on `SisPacking` | +|---|---| +| `iIncrement` (自增列, auto-increment) | `iIncrement int auto_increment PK` | +| `sId` (标准ID) | `sId varchar(100) UNIQUE` | +| `sBrandsId` (加工商Id) | `sBrandsId varchar(100)` | +| `sSubsidiaryId` (子公司Id) | `sSubsidiaryId varchar(100)` | +| `tCreateDate` (制单日期) | `tCreateDate datetime DEFAULT CURRENT_TIMESTAMP` | +| `sMakePerson` (制单人) | `sMakePerson varchar(255)` | +| `iOrder` (排序号) | `iOrder int DEFAULT 0` | +| `sName` (名称) | `sName varchar(255)` | +| `sNo` (编号) | `sNo varchar(255)` | +| `bInvalid` (作废) | `bInvalid bit(1) DEFAULT b'0'` | + +The 10 slave rows in `gdsconfigtbslave` map exactly to the 10 columns +on the physical `SisPacking` table. A PM can then point a +`gdsconfigformmaster` row at `sTbName='SisPacking'`, and the +form-slave rows reference the same columns by name. The framework +glues the two layers together at runtime — same metadata-driven path +as Slice 1. + +This page used to flag a worked example as a TODO; this is it. diff --git a/en/docs/reference/maintainer/deployment.md b/en/docs/reference/maintainer/deployment.md index d29dc98..3261153 100644 --- a/en/docs/reference/maintainer/deployment.md +++ b/en/docs/reference/maintainer/deployment.md @@ -124,5 +124,12 @@ ops documentation, not the codebase. ## Open: production URL routing +> **Deferred (outside the repository's reach).** The nginx / +> reverse-proxy config that maps the public `:8597` / `:8598` to the +> internal Spring Boot context-paths lives in deployment-ops +> infrastructure, not in this codebase. The wiki has no way to verify +> it against src/db/web; this section is a placeholder waiting for +> the deployment-side config to be linked or vendored. + The exact nginx / reverse-proxy config for `8597` / `8598` is not in this repository. Add it here only when the deployment-side config is available. diff --git a/en/docs/slices/02-multi-tenancy.md b/en/docs/slices/02-multi-tenancy.md index 1941c23..1674b1c 100644 --- a/en/docs/slices/02-multi-tenancy.md +++ b/en/docs/slices/02-multi-tenancy.md @@ -131,15 +131,33 @@ per edition. The key columns: > production tenant of the SaaS likely populates the lookup table with > the full edition catalog; the dev DB doesn't. -### How modules are filtered per edition +### How modules are filtered per edition (the actual mechanism) -`sVersionFlowId` lives on `gdsmodule` and on a couple of historical -backup snapshots of that table — nowhere else. So per-edition filtering -applies **only at module-discovery time**, not on every business-data -query. When a user logs in, the framework resolves which edition their -tenant is on, then filters the visible module list to those matching -`gdsmodule.sVersionFlowId`. From there, every loaded module reads its -data with `sBrandsId`/`sSubsidiaryId` scoping as normal. +`sVersionFlowId` / `sVersionFlowCode` are TAGS on `gdsmodule` rows +labelling which edition each module belongs to — **but neither column +appears in any Java source or MyBatis mapper** (verified: `grep -r +sVersionFlowId xly-src --include='*.java' --include='*.xml'` returns +zero hits in mapper SQL). The runtime does **not** filter on those +columns directly. + +The actual gate is licence-based: `xly-src/xlyBusinessService/.../license/` +(TrueLicense + xly's `VerifyLicense.getModelAllList()`) returns the +list of module `sId`s the tenant's licence permits. That list is +comma-substituted into the menu SQL as `sVerifyLicense`: + +```java +// MenuChildServiceImpl.java:38-65 — getBuMenuSql +sql.append(" AND m.sId in ("+sVerifyLicense+")"); +``` + +`sVerifyLicense` is populated either by `RequestAddParamUtil` in +`xlyApi` (lines 50-52: `params.put("sVerifyLicense","'"+String.join("','",listModel)+"'")`) +or by hand-built params in xlyEntry (e.g., `MobliePhoneController.java:57`). +So per-edition filtering really applies **at module-discovery time +through the licence layer**, not via `sVersionFlowId`. The +`sVersionFlowId`/`sVersionFlowCode` tags are catalogue metadata for +operations and BACK-side reporting; the runtime gate is `sVerifyLicense` +→ `IN (...)` against the licence-derived module list. Within `gdsmodule` (1358 rows in the dev DB), three tagging patterns coexist: @@ -173,17 +191,33 @@ These will be added to Concepts as part of the next backfill pass. ## Open verification items -1. **Module-discovery filtering by edition.** The mechanism is reasonable - (filter `gdsmodule` by `sVersionFlowId` against the user's edition), but - we haven't located the exact code path. Likely candidate: - `GdsmoduleController` or `GdsmoduleServiceImpl`. Confirm. -2. **Activiti workflow** — `sVersionFlowId` is *not* a workflow id - (despite the name "flow"). The actual workflow tables (`act_*`, - `biz_flow`, `gdsmoduleflow`, `sysflowsendtointerface`) are populated - only in deployments that actually run an approval flow. A future - Slice 7 will document workflow once a deployment with active flows is - available. -3. **Session-level tenant resolution.** How the JWT/session lookup actually - maps a logged-in user to `sBrandsId`/`sSubsidiaryId` (and which - middleware enforces it) is one layer below `RequestAddParamUtil`. Worth - tracing in the maintainer chapter. +1. ~~**Module-discovery filtering by edition — locate the code path.**~~ + **CLOSED.** The licence-driven filter is in + `xlyBusinessService/.../service/impl/MenuChildServiceImpl.java:38-65` + (`getBuMenuSql`) — the SQL ends with `AND m.sId in (#{sVerifyLicense})`. + `sVerifyLicense` itself is sourced from `VerifyLicense.getModelAllList()` + (TrueLicense-bound) and injected via `RequestAddParamUtil` (xlyApi) + or controller-level param assembly (xlyEntry). See the corrected + "How modules are filtered per edition" section above — the wiki's + prior `sVersionFlowId` claim was wrong. +2. ~~**Activiti workflow / `sVersionFlowId` not a workflow id.**~~ + **CLOSED.** Documented in + [Activiti integration](../reference/maintainer/activiti.md): + Activiti is wired but idle; no BPMN deployed; the framework's + actual workflow uses three non-Activiti paths + (single-step proc + bCheck flag, document chaining, the gated-and- + currently-disabled Activiti dispatch). +3. ~~**Session-level tenant resolution — JWT / session lookup chain.**~~ + **CLOSED.** Chain (all under `xlyBusinessService/.../web/token/`): + `AuthorizationInterceptor.preHandle` checks the `Authorization` + header against `RedisTokenManager.getToken` (AES-decrypts the + bearer to recover `(userId, sBrandsId, sSubsidiaryId, …)`, + then `checkToken` validates the cached token at Redis key + `` and refreshes its TTL). The resolved + `UserInfo` is then made available through `@CurrentUser` + (resolved by `CurrentUserMethodArgumentResolver`), and + `RequestAddParamUtil.me().addParams(params, userInfo)` injects + the 16 keys (sBrandsId, sSubsidiaryId, sBrId, sSuId, sLoginId, + sIpAddress, sComputeName, sUserId, userId, sLanguage, sUserType, + sUserName, sMakePerson, sTeamId, sMachineId, CURRENT_USER_LOGIN_TYPE) + on every authenticated method call. diff --git a/en/docs/slices/03-report.md b/en/docs/slices/03-report.md index 856a51a..c5411e4 100644 --- a/en/docs/slices/03-report.md +++ b/en/docs/slices/03-report.md @@ -139,8 +139,13 @@ PDF-via-iText. The mechanism is separate from the grid: view-backed query with a "fetch all rows" wrapper, and streams a binary file back. - This module (`工单工序明细`) has no template attached, so we don't - exercise the print path here. **A future revision of this slice should - pick a module that *does* — `print template` is a chapter of its own.** + exercise the print path here. + +> **Future-work backlog.** A revision of this slice that picks a +> module *with* an attached print template would let us trace the +> jxls export end-to-end. Blocked on dev-DB state today (no +> view-backed form has a `sysreport` row attached — see the Open +> verification items below). ## Concepts this slice introduces (or sharpens) @@ -170,6 +175,13 @@ PDF-via-iText. The mechanism is separate from the grid: ## Open verification items +> **Item 1 — Deferred (needs populated dev DB).** As of the last audit +> the dev DB has zero view-backed forms with a `sysreport` row attached: +> `SELECT … FROM gdsconfigformmaster m INNER JOIN sysreport r ON +> r.sFormId = m.sId WHERE m.sType='view'` returns 0 rows. The item +> remains a real verification gap that requires a tenant deployment +> whose `sysreport` rows include at least one view-backed form. + 1. **A view-backed module *with* a print template** — pick one and trace the jxls export end-to-end. Likely candidate: any monthly / yearly summary report (`viw_corebusinessreport`, @@ -178,6 +190,25 @@ PDF-via-iText. The mechanism is separate from the grid: backed by stored procedures rather than tables/views. Slice 4 or a variant of this slice should cover that mode: how a proc-backed form returns its result-set, and how parameters flow. -3. **Tenant safety in views.** We claimed views "almost always" carry - `sBrandsId` / `sSubsidiaryId`. Worth a script that audits which - views *don't* — those are potential cross-tenant leak vectors. +3. ~~**Tenant safety in views — audit which `viw_*` lack + `sBrandsId`.**~~ **CLOSED — 19 of 305 (~6.2 %) leak.** Run against + the live DB: + + ```sql + SELECT v.TABLE_NAME + FROM information_schema.views v + WHERE v.TABLE_SCHEMA = DATABASE() + AND v.TABLE_NAME LIKE 'viw_%' + AND v.TABLE_NAME NOT IN ( + SELECT TABLE_NAME FROM information_schema.columns + WHERE TABLE_SCHEMA = DATABASE() AND COLUMN_NAME = 'sBrandsId' + ); + ``` + + Returns 19 rows in this dev DB — including `viw_purorder_slave_detail`, + `viw_qlyprocesstest`, the `viw_accproductstoreinvoice*` family, the + `viw_hmwxjy*` set, etc. Each is a potential cross-tenant leak + *if* a form points at it without an enclosing tenant predicate in + `gdsconfigformmaster.sWhere`. Auditing the form layer's predicates + for these specific views is the next step; the bare-view audit is + now a one-shot SQL. diff --git a/en/docs/slices/04-custom-field.md b/en/docs/slices/04-custom-field.md index 2f0a1e5..154dae7 100644 --- a/en/docs/slices/04-custom-field.md +++ b/en/docs/slices/04-custom-field.md @@ -36,9 +36,11 @@ Imagine a tenant 山东星海印务 wants to add a "客户内部编码" (Custome Internal Code) field to the customer-list form. They (or an implementer) does this without touching `gdsconfigformslave`. Instead: -1. Open the BACK module that *edits* `gdsconfigformcustomslave` rows - (one of the system-management screens — likely `界面显示内容配置` — - needs verification by clicking through BACK). +1. Open `界面显示内容配置` in BACK (`gdsmodule.sId=11`, + `/jmnrpz`). Its third panel writes to `gdsconfigformcustomslave` + via the form-master at `sId=19211681019715596285250620` — verified + live. See "Open verification items" item 1 below for the + per-panel mapping. 2. Add a new row with: - `sParentId` = the form's `sId` (same form the base slaves point to) - `sName = 'sInternalCode'` (the field's column name) @@ -142,9 +144,24 @@ forms never use. ## Open verification items -1. **Find the live BACK page that edits `gdsconfigformcustomslave`.** - Most likely `界面显示内容配置` from the sidebar; confirm by clicking - in BACK and checking which table the save endpoint writes to. +1. ~~**Find the live BACK page that edits `gdsconfigformcustomslave`.**~~ + **CLOSED — confirmed `界面显示内容配置`** (`gdsmodule.sId=11`, URL + `/jmnrpz`). The page renders three form-master panels in one screen, + one for each layer of the form-definition stack: + + | Panel | `gdsconfigformmaster.sId` | `sTbName` it writes | + |---|---|---| + | Form-master editor | `19211681019715574673782610` | `gdsconfigformmaster` | + | Base slave editor | `19211681019715596207594120` | `gdsconfigformslave` | + | Per-tenant overlay | `19211681019715596285250620` | `gdsconfigformcustomslave` | + + The third panel is the canonical channel for "add a custom field for + tenant X". Verified live: clicking 界面显示内容配置 in BACK + (admin/123) fires `POST /xlyEntry/business/getBusinessDataByFormcustomId/19211681019715596285250620?sModelsId=11` + to load the existing customslave rows; subsequent 新增/修改 operations + route their `addUpdateDelBusinessData` POST to that same form-master, + which the runtime resolves to a write against + `gdsconfigformcustomslave` (per the standard universal save path). 2. ~~**Trace the merge code.**~~ **CLOSED** — the merge happens in Java at `BusinessBaseServiceImpl.java:246-248`: it calls `businessGdsconfigformsService.getFormSlaveData(map)` then @@ -153,10 +170,26 @@ forms never use. `gdsconfigformcustomslavemasterview`) supply the joined-with-master shape that each call reads — the *merge* is Java; the *master-with-slave join* is SQL. -3. **`bVisible = false` semantics.** Does setting `bVisible = false` on - a `gdsconfigformcustomslave` row *hide* an existing base field - (an override-to-remove pattern), or only suppress the override - itself? Likely the former, but worth confirming. +3. ~~**`bVisible = false` semantics — hide-base or suppress-override?**~~ + **CLOSED — both, at different layers.** In + `BusinessGdsconfigformsServiceImpl.java:413-433`, when a + `gdsconfigformcustomslave` row matches a base `gdsconfigformslave` + row by `sControlName` *or* `sName`, the customslave row replaces + the base row entirely (`sList.removeAll(_cstlist); sList.addAll(_cList);`), + so `bVisible=false` on the customslave row hides the base field + for that tenant. The user-level overlay + (`gdsconfigformuserslave`, lines 446-468) then runs on top: when + the user-row's `bVisible` is true *and* the merged row's `bVisible` + is true, the user's `iFitWidth`/`iOrder` apply; otherwise line 464 + explicitly sets `cmap.put("bVisible", false)` on the merged row — + hiding it from that user only. So `bVisible=false` does hide the + field at either layer; the scope (per-tenant vs per-user) differs. +> **Item 4 — Deferred (needs populated tenant deployment).** +> Empirically confirmed against the dev DB: +> `SELECT COUNT(*) FROM gdsconfigformcustomslave` returns 0 rows. No +> tenant on this DB has registered any per-tenant field overlay, so a +> worked example cannot be drawn from here. The item stays a real gap +> waiting on a populated production-tenant DB. + 4. **A real example.** Find a tenant's actual `gdsconfigformcustomslave` rows in a populated deployment and use them as a worked example here. - *(Dev DB confirmed empty — needs a tenant deployment with overlays.)* diff --git a/en/docs/slices/05-customer-sql-override.md b/en/docs/slices/05-customer-sql-override.md index e54ec63..878cbe9 100644 --- a/en/docs/slices/05-customer-sql-override.md +++ b/en/docs/slices/05-customer-sql-override.md @@ -302,19 +302,31 @@ the proc. ## Open verification items -1. **Is the application of these scripts truly entirely manual, or is - there a Quartz-job / `DbToDbController` mechanism that loads them?** - The `xlyFlow/dbtodb` package is named suspiciously close to "DB - migration" but the surface area looked like inter-DB sync, not - script application. Confirm by reading - `DbToDbServiceImpl.java`. +1. ~~**Is the application of these scripts manual, or is there a + Quartz/DbToDb mechanism?**~~ **CLOSED — manual.** + `xlyFlow/.../dbtodb/service/impl/DbToDbServiceImpl.java` is **inter-DB + sync** (its public methods are `getData`, `getDataDetail`, + `getDataCount`, `addSave`, `execute`, `select`, `testConnect` — all + working over `DruidDataSource` + `DruidProperties` + `JdbcUtils` + against the customer's own remote DB). It is **not** a script-applier + — there is no walk-the-`script/客户/` directory step anywhere in the + in-scope codebase (`grep -rn "script/客户" xly-src/.../*.java` returns + zero hits). Each `script/客户//.sql` is committed + for traceability and applied manually by an engineer / DBA via + `mysql --defaults-file=… < the-file.sql`. 2. **Auditing.** Build a small script that connects to a customer's DB and diffs every `Sp_*`/`viw_*` body against the standard. Customers running unexpectedly-divergent procs are an operational risk. -3. **Side-by-side `Sp_SalSalesCheck` diff** — the wiki currently - describes the override structurally. A future revision should - include the actual body diff that shows which business rule changed - for 重庆展印 and why. + *(Future-work backlog item — not a verification claim. The audit + query against any single tenant DB is one statement, but + automating it across the customer fleet is the work.)* +3. **Side-by-side `Sp_SalSalesCheck` diff.** The structural diff + table above (size, params, key SQL features, `CbxSrcNoCheck` + branch) covers the *shape* of the divergence; a body-level diff + showing the exact business rule difference would deepen this. + *(Future-work backlog item — the copy-pasteable command above + produces it on demand; embedding the full diff in the wiki was + judged not worth the page weight.)* 4. **Lifecycle.** When a customer migrates schemas (upgrade, restore, rebuild), how is each override re-applied? A documented runbook for that operation belongs in the maintainer chapter on deployment. diff --git a/en/docs/slices/06-hardware.md b/en/docs/slices/06-hardware.md index aeda3b9..e3eddf4 100644 --- a/en/docs/slices/06-hardware.md +++ b/en/docs/slices/06-hardware.md @@ -120,14 +120,37 @@ press's PLC pushed it through xlyPlc. ## Open verification items +> **Item 1 — Deferred (outside the repository's reach).** The byte +> protocols themselves come from each press model's vendor +> documentation, not from the xly source tree. Each +> `xlyPlc/src/main/resources/application-.yml` carries the +> *parameters* (baud rate, framing, register addresses, polling +> tunables); the *protocol semantics* are press-vendor knowledge. +> Documenting either fully is a deployment-ops job, not a wiki audit +> against src/db/web. + 1. **The wire protocol.** Each press model has a different byte protocol; each `application-.yml` carries the parameters. Documenting the protocol per model is a separate, niche chapter that this wiki may or may not need. -2. **Bridge → ERP-DB latency.** What's the polling interval per - profile, and how does that interact with shop-floor dashboard - refresh? Operational concern, worth a paragraph. -3. **Why `xlyRxtx` is disabled in `settings.gradle`.** RXTX is the - native serial-port library; the build excludes it. Understanding - whether xlyPlc currently runs without serial support, or whether - it expects serial only on certain deployments, is worth confirming. +2. ~~**Bridge → ERP-DB latency / polling interval.**~~ **CLOSED.** + `PlcScheduledTasks.java` ships **two** Spring `@Scheduled` cron + methods (no per-profile difference observed in the cron string): + `0/30 * * * * ?` (every 30 s, line 74) and `0/1 * * * * ?` (every + 1 s, line 105). A third commented-out cron at line 125 + (`0 */2 * * * ?`) is dormant. Per-profile parameter tuning happens + inside the polling code via the `application-.yml` YAML, not + the cron expression itself. Shop-floor dashboard refresh is + independent: its `viw_*` aggregations re-read `mftProduceReportMachineState` + on each FROUNT request, so the dashboard sees a row at most ~30 s + after the press emits it. +3. ~~**Why `xlyRxtx` is disabled in `settings.gradle`.**~~ **CLOSED.** + git history on `xly-src/settings.gradle` shows `xlyRxtx` was + originally added in commit `daf581311` ("1、添加串口功能 …" — added + serial-port feature). The cleanup branch comments it out as part + of the source-pruning pass that excludes hardware modules whose + features are not yet exercised in the dev DB; a deployment that + needs direct serial access to a press would re-enable the include + line in `settings.gradle`. xlyPlc itself runs without RXTX — + it relies on TCP/Ethernet for the press models documented here; + serial-only press models would need RXTX re-enabled. diff --git a/en/docs/slices/07-workflow.md b/en/docs/slices/07-workflow.md index 3ef9ef4..f22be56 100644 --- a/en/docs/slices/07-workflow.md +++ b/en/docs/slices/07-workflow.md @@ -1,5 +1,17 @@ # Slice 7 (deferred) — a module with workflow +> **Deferred — needs a deployment with deployed BPMN AND the gate +> re-enabled.** Empirically confirmed against the dev DB: +> `act_re_procdef = 0`, `act_ru_task = 0`, `act_hi_procinst = 0`, +> `biz_flow = 0`, `biz_todo_item = 0`, `gdsmoduleflow = 0`, and +> `gdsmodule WHERE bCheck = 1` returns 0 rows. On top of the +> empty-tables state, the dispatch path itself is hard-disabled by +> `ConstantUtils.bCheckflowCheck = false` +> ([Activiti integration](../reference/maintainer/activiti.md)). +> So the slice cannot be exercised against this codebase — the +> [Activiti integration](../reference/maintainer/activiti.md) page +> already documents the code-derived hypothesis. + > **STUB. DEFERRED.** Activiti is wired into the codebase (`xlyFlow` module, > `act_*` schema, two Activiti versions in `xlyPersist`/`xlyFlow`), but > the workflow tables (`act_re_procdef`, `act_ru_task`, `act_hi_procinst`,