diff --git a/en/docs/reference/maintainer/activiti.md b/en/docs/reference/maintainer/activiti.md
index c252c6a..d4861df 100644
--- a/en/docs/reference/maintainer/activiti.md
+++ b/en/docs/reference/maintainer/activiti.md
@@ -156,6 +156,19 @@ the instance.
| Currently active | Yes, on every 审核 click | Yes, in every multi-document business flow | No — `bCheckflowCheck = false` in code |
| Tooling | Just a stored proc | Stored procs + module-tree configuration | BPMN modeler at `/modeler/*` |
+### A real Path-1 customisation example
+
+[Slice 5](../../slices/05-customer-sql-override.md#worked-example-2-builds-a-multi-level-approval-workflow)
+walks through 万昌's `领班驳回.sql` — a customer-side multi-level
+approval rejection. It's the canonical example of how customers
+extend Path 1 when the single-`bCheck` flag isn't enough: they
+`ALTER TABLE` to add multiple approval flags (`bManager`, `bIPQC`,
+`bDeputy`, …), write transition procs following the
+`Sp_
_check_` naming convention, and
+emit audit entries via a custom `sp_add_flow_log`. This is the
+empirically-observed customisation channel — Activiti deployment
+is not seen in any `script/客户/` directory.
+
### Why this design works for xly's audience
The printing-industry ERP customers run rule-driven business
diff --git a/en/docs/slices/05-customer-sql-override.md b/en/docs/slices/05-customer-sql-override.md
index 23ad3bc..e54ec63 100644
--- a/en/docs/slices/05-customer-sql-override.md
+++ b/en/docs/slices/05-customer-sql-override.md
@@ -143,6 +143,140 @@ mysql --defaults-file=$HOME/.my.cnf xlyweberp_saas_ai \
diff /tmp/std.sql script/客户/重庆展印/Sp_SalSalesCheck.sql | head -200
```
+## Worked-example 2: 万昌 builds a multi-level approval workflow
+
+The 重庆展印 example above replaces *one* proc body. The
+**`script/客户/万昌/`** directory shows a more ambitious pattern: the
+customer extends the schema and builds a multi-level approval
+workflow that the standard framework doesn't ship.
+
+The customisation tree (excerpt):
+
+```
+script/客户/万昌/
+├── 计件工资/
+│ ├── 日报审核/
+│ │ └── 领班驳回.sql ← this slice's anchor
+│ ├── 报表/
+│ │ ├── 包装补时.sql
+│ │ ├── 员工大废品.sql
+│ │ ├── 班组大废品率查询报表.sql
+│ │ ├── 手工质检组返工.sql
+│ │ └── Sp_Manual_quality_inspection_rework.sql
+│ └── 计件工资核算/
+│ ├── 计件工资/
+│ │ ├── sp_piece_rate_j.sql
+│ │ ├── sp_piece_rate_JZ.sql
+│ │ ├── sp_piece_rate_other.sql
+│ │ └── sp_piece_rate_w.sql
+│ ├── 员工工资汇总查询/员工工资汇总查询.sql
+│ ├── Sp_BtnEven_CalcJsHs.sql
+│ └── sp_btn_WorkOrderAssessmentPassRate.sql
+├── Sp_getworkorder_calc_cb.sql
+└── …
+```
+
+The Chinese-named subdirectories (`计件工资`/`日报审核` = "piece-rate
+wages / daily-report approval") encode the customer's organisational
+flow into the file system itself. A maintainer reading `ls` knows
+which business process each script belongs to.
+
+### What the rejection script actually does
+
+`领班驳回.sql` ("Foreman Rejection") is 185 lines defining
+`Sp_mftproductionreportmaster_check1_0`. The naming is xly's
+state-transition convention: `Sp__check_`,
+so `check1_0` means "transition from state 1 (approved) back to
+state 0 (draft)" — i.e., a rejection.
+
+Trimmed body of the central UPDATE:
+
+```sql
+SET p_setSql = CONCAT('bManager = 0,
+ bIPQC = 0,
+ bDeputy = 0,
+ bSubmit = 0,
+ bWorkshopManager = 0,
+ bCheck = 0,
+ sRejectMemo = ''', p_sRejectMemo, ''',
+ sMReserve1 = ', p_textareaValue);
+
+Set @sSqlStmt = CONCAT('Update mftproductionreportmaster
+ Set ', p_setSql, '
+ Where sId = ''', p_sTmpId, '''
+ AND sBrandsId = ''', sBrId, '''
+ AND sSubsidiaryId = ''', sSuId, '''');
+PREPARE sSqlStmt FROM @sSqlStmt;
+EXECUTE sSqlStmt;
+
+CALL sp_add_flow_log(p_sTmpId, p_sTmpId, '驳回', '驳回', '驳回',
+ sMakePerson, p_sRejectMemo, @sReturn, @sCode);
+```
+
+So one button click resets **six** approval flags simultaneously,
+appends to a per-row rejection-reason history, and writes to a
+custom audit log.
+
+### What's customer-side and not in standard
+
+Verified against the dev DB recon target (`xlyweberp_saas_ai`):
+
+| Customisation | Standard schema? | 万昌 needs to add it |
+|---|---|---|
+| Multi-level approval columns: `bManager`, `bIPQC`, `bDeputy`, `bSubmit`, `bWorkshopManager` on `mftproductionreportmaster` | **No** — only `bCheck`, `sCheckPerson`, `tCheckDate` exist. | Yes — `ALTER TABLE` to add 5 boolean columns. |
+| `sRejectMemo` rejection-reason history column | **No** | Yes — `ALTER TABLE` to add a longtext. |
+| `sp_add_flow_log` audit-log proc | **No** — does not exist in standard. | Yes — wholly customer-defined. |
+| Naming convention `Sp__check_` | **No** — no procs in DB use this pattern. | Yes — 万昌's convention. |
+| Hook into the framework's button machinery | Yes — `gdsconfigformslave.sButtonParam` points at the proc name. | (configuration only) |
+
+So 万昌's "Foreman Rejection" workflow is **a customer-built
+state-machine atop xly's button primitive**: schema extension +
+custom procs + custom audit log. The framework provides only the
+button-press dispatch (via `/business/genericProcedureCall*` or the
+button-param hook on the form-slave). Everything else — what state
+the document is in, what flags toggle, what audit text gets logged —
+is customer-side.
+
+This is fundamentally different from how Activiti would solve the
+same problem (BPMN graph + assignee model + Activiti's task table).
+xly's framework lets the customer choose either model:
+- **Activiti style**: deploy a BPMN, link via `gdsmoduleflow`,
+ flip `ConstantUtils.bCheckflowCheck = true` (see
+ [activiti.md](../reference/maintainer/activiti.md#path-3-activiti-bpmn-workflow-gated-currently-disabled-in-code)).
+- **万昌 style**: extend the schema, write transition procs, drop
+ them under `script/客户///`, apply manually.
+
+The 万昌 style is what the codebase actually shows in production-
+adjacent customisations — Activiti is wired but no customer
+directory under `script/客户/` deploys a BPMN, while 万昌-style
+schema-extending workflows DO show up. That's the empirical answer
+to "how is workflow customised in this repo?": **schema-extending
+stored procs delivered via per-customer override scripts**.
+
+### Customer customisation patterns at a glance
+
+Of the 18 customer override directories, most don't customise
+*workflow* per se — they customise **calculations and reports**.
+The breakdown of what each directory contains:
+
+- `万昌` (14 files): includes the `领班驳回.sql` workflow extension,
+ plus piece-rate wage calculation procs.
+- `千彩` (50 files): the most heavily customised customer. Mostly
+ per-tenant calculation overrides (`Sp_Calc_*`, `Sp_Inventory_*`,
+ `Sp_Manufacture_*`) and one workflow-list view
+ (`viw_NoSalSalesChecking`).
+- `重庆展印` (2 files): replacement of one sales-check proc + a
+ companion view, as documented above.
+- `朝阳` (8), `金宣发` (8), `无锡中江` (8), `亚明威` (6), `福雅` (5),
+ `金九` (5), `快马` (4), and others: smaller calc / report
+ overrides.
+
+So the workflow customisation pattern (schema extension + transition
+procs + custom audit) is **rare** — it's worth doing only when the
+customer's process genuinely doesn't fit a single-step approval and
+the standard framework's `bCheck` toggle isn't enough. Most customer
+divergence is calculation logic, not workflow shape.
+
The companion view `viw_salsaleschecking_pro.sql` exists for the same
reason — when the override needs a join shape the standard doesn't
provide, the engineer authors a customer-specific view, drops it into