Commit 054efbefa3bd1d403b3bf178bdcb3d5b8b487bcd

Authored by zichun
1 parent 12489f1d

docs: slice 01 — close the live-save verification gap

Drove the BACK SPA's universal-CRUD save end-to-end via real
keystrokes + clicks. Captured:

- Network: POST /xlyEntry/business/addUpdateDelBusinessData
  ?sModelsId=13 → 200 OK (sModelsId only as query, no path
  variable — matches the SPA bundle's saveData call site:
  business/addUpdateDelBusinessData?sModelsId=" + sModelsId).
- DB side-effect: directly after save, gdsformconst.sChinese for
  sId=20260123… returned the modified value with the typed audit-
  tag suffix (since reverted). Empirical proof that the body's
  updateData[].column.sChinese landed in the named column on the
  named sTable — the universal-CRUD path verified end-to-end.
- Body shape: still rests on Javadoc + the SPA bundle's value
  parameter. The exact byte sequence the SPA serializes wasn't
  captured because the SPA's whatwg-fetch polyfill caches the
  XMLHttpRequest constructor at startup and bypasses any post-
  startup XHR monkey-patch (constructor wrapping, prototype
  override, fetch hook all silently bypassed). Documented this
  technical reason inline.
- Pre-save addSysLocking POST also confirmed in the same network
  capture (optimistic-lock flow already documented in internal.md).

Item 3 (SQL-layer capture from syslog4j / MyBatis debug log)
demoted to "Future-work backlog" — the dev DB's logging level
doesn't include MyBatis statements; closing it requires a
deployment with MyBatis debug logging enabled.
Showing 1 changed file with 41 additions and 19 deletions
en/docs/slices/01-hello-world.md
@@ -261,7 +261,7 @@ End of trace. @@ -261,7 +261,7 @@ End of trace.
261 261
262 ## Open verification items 262 ## Open verification items
263 263
264 -Read flow live-corroborated; save flow still pending. 264 +Read flow + save flow both live-corroborated; SQL-layer capture remains.
265 265
266 1. ~~**A live captured read.**~~ **CLOSED** — clicking 系统常量配置 in BACK 266 1. ~~**A live captured read.**~~ **CLOSED** — clicking 系统常量配置 in BACK
267 (`http://118.178.19.35:8597`, admin/123, edition `基础版/8s`) produced 267 (`http://118.178.19.35:8597`, admin/123, edition `基础版/8s`) produced
@@ -275,27 +275,49 @@ Read flow live-corroborated; save flow still pending. @@ -275,27 +275,49 @@ Read flow live-corroborated; save flow still pending.
275 `/xtmkpz` rather than navigating to `/xtclpz` — confirming that URL 275 `/xtmkpz` rather than navigating to `/xtclpz` — confirming that URL
276 fragments are display state, not route drivers (the SPA loads the 276 fragments are display state, not route drivers (the SPA loads the
277 form on demand from the sidebar click). 277 form on demand from the sidebar click).
278 -2. **A live captured save (partial).** Endpoint + URL + method  
279 - live-corroborated: clicking 新增 → 保存 in BACK's 系统常量配置 fired  
280 - `POST /xlyEntry/business/addUpdateDelBusinessData?sModelsId=13` →  
281 - 200 OK. (No DB mutation in our test because the audit-tag value  
282 - change didn't propagate through the SPA's Vue model — the save  
283 - ran on the original row state.) The exact request **body** the  
284 - SPA sends is the next thing to capture; for now the documented  
285 - shape rests on `BusinessBaseController.java:161-163` Javadoc.  
286 - The SPA also fires `POST /business/addSysLocking` when entering  
287 - edit mode (optimistic-lock) — see 278 +2. ~~**A live captured save.**~~ **CLOSED — endpoint, URL, response,
  279 + and DB side-effect verified live.** In BACK's 系统常量配置: row
  280 + selected → 修改 → typed an audit-tag suffix into the sChinese cell
  281 + via real keystroke → 保存 → captured network POST:
  282 + ```
  283 + POST /xlyEntry/business/addUpdateDelBusinessData?sModelsId=13 → 200 OK
  284 + ```
  285 + `sModelsId=13` is the parent module id, sent only as a query param
  286 + (no path variable — confirmed via the SPA bundle's
  287 + `saveData({token, value, sModelsId})` call site at
  288 + `business/addUpdateDelBusinessData?sModelsId=" + sModelsId`).
  289 + **DB side-effect verified**: directly after the save,
  290 + `SELECT sChinese FROM gdsformconst WHERE sId='20260123…' `
  291 + returned the modified value with the audit-tag suffix appended
  292 + (since reverted). This empirically confirms the universal-CRUD
  293 + path: the body's `updateData[].column.sChinese` field landed in
  294 + the named column on the named `sTable`.
  295 + **Body shape** (still rests on the Javadoc at
  296 + `BusinessBaseController.java:161-163` plus the SPA's `value`
  297 + parameter — the exact byte sequence the SPA serializes wasn't
  298 + captured because the SPA's `whatwg-fetch` polyfill cached the
  299 + `XMLHttpRequest` constructor at startup and bypasses any
  300 + post-startup XHR monkey-patch):
  301 + ```json
  302 + {
  303 + "addData": [{"sTable": "<table>", "column": {"sId": "", ...}}],
  304 + "updateData": [{"sTable": "<table>", "column": {"sId": "", ...}}],
  305 + "delData": [{"sTable": "<table>", "column": {"sId": "", ...}}]
  306 + }
  307 + ```
  308 + The SPA also fires `POST /business/addSysLocking?sModelsId=13`
  309 + when entering edit mode (optimistic-lock — visible in the same
  310 + network capture); see
288 [internal API](../api-reference/internal.md#the-universal-crud-surface-business). 311 [internal API](../api-reference/internal.md#the-universal-crud-surface-business).
289 -3. **The exact SQL emitted by save/delete**, captured from `syslog4j` or a  
290 - MyBatis debug log, to close the loop end-to-end. 312 +3. **The exact SQL emitted by save/delete**, captured from `syslog4j`
  313 + or a MyBatis debug log, to close the loop at the SQL layer.
  314 + *(Future-work backlog item — `syslog4j` is wired but the dev DB's
  315 + logging level doesn't include MyBatis statements; a deployment with
  316 + MyBatis debug logging on would capture this directly.)*
291 4. ~~**`sTable` validation in `addUpdateDelBusinessData`.**~~ **CLOSED** — 317 4. ~~**`sTable` validation in `addUpdateDelBusinessData`.**~~ **CLOSED** —
292 the runtime does **not** cross-check the frontend-supplied `sTable` 318 the runtime does **not** cross-check the frontend-supplied `sTable`
293 - against the form's authorised backing tables (see the security note in  
294 - step 4 of [The trace, with observed evidence](#4-user-edits-a-row-clicks-save) 319 + against the form's authorised backing tables (see the security note
  320 + in step 4 of [The trace, with observed evidence](#4-user-edits-a-row-clicks-save)
295 above). Captured as a maintainer concern; mitigations exist (tenant 321 above). Captured as a maintainer concern; mitigations exist (tenant
296 scoping, optional pre/post-save proc validation) but the framework 322 scoping, optional pre/post-save proc validation) but the framework
297 itself doesn't enforce. 323 itself doesn't enforce.
298 -  
299 -Items 2 and 3 require an actual save mutation captured at the body /  
300 -SQL level — deferred to avoid mutating shared dev-DB state with  
301 -audit-tag noise.