cabloy 5.1.60 → 5.1.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/.claude/hooks/contract-loop-gate.ts +296 -0
  2. package/.claude/settings.json +16 -0
  3. package/.claude/skills/cabloy-backend-scaffold/SKILL.md +2 -0
  4. package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -0
  5. package/.claude/skills/cabloy-contract-loop/SKILL.md +89 -16
  6. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
  7. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
  8. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
  9. package/.claude/skills/cabloy-domain-planning/SKILL.md +212 -0
  10. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -0
  11. package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
  12. package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
  13. package/.claude/skills/cabloy-resource-field-update/SKILL.md +7 -0
  14. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
  15. package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
  16. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
  17. package/CHANGELOG.md +64 -0
  18. package/CLAUDE.md +11 -0
  19. package/cabloy-docs/.vitepress/config.mjs +197 -5
  20. package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
  21. package/cabloy-docs/ai/docs-skills-rules-mapping.md +22 -0
  22. package/cabloy-docs/ai/future-skill-roadmap.md +12 -7
  23. package/cabloy-docs/ai/introduction.md +1 -0
  24. package/cabloy-docs/ai/playbook-backend-module.md +6 -0
  25. package/cabloy-docs/ai/playbook-module-removal.md +164 -0
  26. package/cabloy-docs/ai/skills.md +12 -0
  27. package/cabloy-docs/backend/backend-contract-emission-output-inspection.md +189 -0
  28. package/cabloy-docs/backend/backend-contract-emission-source-reading-map.md +160 -0
  29. package/cabloy-docs/backend/backend-contract-emission-specimen.md +170 -0
  30. package/cabloy-docs/backend/backend-resource-module-contract-chain.md +323 -0
  31. package/cabloy-docs/backend/backend-source-reading-debug-checklist.md +173 -0
  32. package/cabloy-docs/backend/backend-source-reading-roadmap.md +129 -0
  33. package/cabloy-docs/backend/backend-source-reading-verify-playbook.md +166 -0
  34. package/cabloy-docs/backend/bean-scene-authoring.md +4 -4
  35. package/cabloy-docs/backend/broadcast-guide.md +3 -3
  36. package/cabloy-docs/backend/cli.md +20 -11
  37. package/cabloy-docs/backend/config-guide.md +4 -4
  38. package/cabloy-docs/backend/controller-aop-guide.md +10 -10
  39. package/cabloy-docs/backend/controller-guide.md +12 -2
  40. package/cabloy-docs/backend/crud-workflow.md +7 -3
  41. package/cabloy-docs/backend/dto-guide.md +18 -2
  42. package/cabloy-docs/backend/dto-infer-generation.md +201 -25
  43. package/cabloy-docs/backend/election-guide.md +2 -2
  44. package/cabloy-docs/backend/entity-guide.md +30 -3
  45. package/cabloy-docs/backend/error-guide.md +3 -3
  46. package/cabloy-docs/backend/event-guide.md +4 -4
  47. package/cabloy-docs/backend/external-aop-guide.md +2 -2
  48. package/cabloy-docs/backend/field-indexes.md +9 -3
  49. package/cabloy-docs/backend/foundation.md +8 -8
  50. package/cabloy-docs/backend/i18n-guide.md +6 -6
  51. package/cabloy-docs/backend/internal-aop-guide.md +2 -2
  52. package/cabloy-docs/backend/introduction.md +15 -0
  53. package/cabloy-docs/backend/migration-and-changes.md +3 -3
  54. package/cabloy-docs/backend/model-guide.md +16 -6
  55. package/cabloy-docs/backend/openapi-guide.md +3 -0
  56. package/cabloy-docs/backend/queue-guide.md +3 -3
  57. package/cabloy-docs/backend/redlock-guide.md +2 -2
  58. package/cabloy-docs/backend/schedule-guide.md +2 -2
  59. package/cabloy-docs/backend/scripts.md +8 -0
  60. package/cabloy-docs/backend/serialization-guide.md +12 -2
  61. package/cabloy-docs/backend/service-guide.md +18 -9
  62. package/cabloy-docs/backend/startup-guide.md +5 -5
  63. package/cabloy-docs/backend/status-guide.md +271 -0
  64. package/cabloy-docs/backend/unit-testing.md +3 -3
  65. package/cabloy-docs/backend/vona-source-reading-map.md +157 -0
  66. package/cabloy-docs/backend/websocket-protocol-guide.md +5 -5
  67. package/cabloy-docs/backend/websocket-usage-guide.md +15 -8
  68. package/cabloy-docs/frontend/a-model-under-the-hood.md +281 -0
  69. package/cabloy-docs/frontend/a-openapi-under-the-hood.md +248 -0
  70. package/cabloy-docs/frontend/a-router-guide.md +307 -0
  71. package/cabloy-docs/frontend/api-guide.md +6 -4
  72. package/cabloy-docs/frontend/api-schema-guide.md +1 -0
  73. package/cabloy-docs/frontend/app-startup-guide.md +7 -4
  74. package/cabloy-docs/frontend/bean-scene-authoring.md +3 -1
  75. package/cabloy-docs/frontend/behavior-guide.md +16 -16
  76. package/cabloy-docs/frontend/cli.md +14 -2
  77. package/cabloy-docs/frontend/command-scene-authoring.md +504 -0
  78. package/cabloy-docs/frontend/component-guide.md +5 -5
  79. package/cabloy-docs/frontend/component-props-guide.md +1 -1
  80. package/cabloy-docs/frontend/component-v-model-guide.md +2 -2
  81. package/cabloy-docs/frontend/design-principles.md +6 -0
  82. package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
  83. package/cabloy-docs/frontend/filter-query-select-data-flow-guide.md +260 -0
  84. package/cabloy-docs/frontend/form-guide.md +786 -0
  85. package/cabloy-docs/frontend/form-scene-to-page-meta-guide.md +303 -0
  86. package/cabloy-docs/frontend/foundation.md +33 -0
  87. package/cabloy-docs/frontend/frontend-source-reading-roadmap.md +249 -0
  88. package/cabloy-docs/frontend/generated-contract-consumption-debug-checklist.md +190 -0
  89. package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +205 -0
  90. package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +157 -0
  91. package/cabloy-docs/frontend/generated-contract-consumption-specimen.md +203 -0
  92. package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +189 -0
  93. package/cabloy-docs/frontend/generic-component-guide.md +1 -1
  94. package/cabloy-docs/frontend/introduction.md +38 -5
  95. package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
  96. package/cabloy-docs/frontend/mock-guide.md +1 -0
  97. package/cabloy-docs/frontend/model-architecture.md +288 -39
  98. package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
  99. package/cabloy-docs/frontend/model-resource-cookbook.md +508 -0
  100. package/cabloy-docs/frontend/model-resource-internals-deep-dive.md +238 -0
  101. package/cabloy-docs/frontend/model-resource-owner-pattern.md +402 -0
  102. package/cabloy-docs/frontend/model-resource-usage-guide.md +334 -0
  103. package/cabloy-docs/frontend/model-state-guide.md +371 -15
  104. package/cabloy-docs/frontend/module-scope.md +8 -8
  105. package/cabloy-docs/frontend/modules-and-suites.md +2 -1
  106. package/cabloy-docs/frontend/navigation-guards-guide.md +7 -0
  107. package/cabloy-docs/frontend/openapi-sdk-guide.md +17 -6
  108. package/cabloy-docs/frontend/page-guide.md +15 -9
  109. package/cabloy-docs/frontend/page-meta-guide.md +466 -0
  110. package/cabloy-docs/frontend/page-params-guide.md +3 -3
  111. package/cabloy-docs/frontend/page-query-guide.md +2 -2
  112. package/cabloy-docs/frontend/page-route-guide.md +6 -0
  113. package/cabloy-docs/frontend/permission-formscene-action-visibility-guide.md +263 -0
  114. package/cabloy-docs/frontend/quickstart.md +18 -2
  115. package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
  116. package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +271 -0
  117. package/cabloy-docs/frontend/resource-list-page-deep-dive.md +279 -0
  118. package/cabloy-docs/frontend/rest-resource-source-reading-map.md +522 -0
  119. package/cabloy-docs/frontend/rest-resource-under-the-hood.md +622 -0
  120. package/cabloy-docs/frontend/root-behaviors-guide.md +282 -0
  121. package/cabloy-docs/frontend/route-alias-guide.md +6 -0
  122. package/cabloy-docs/frontend/router-stack-guide.md +229 -0
  123. package/cabloy-docs/frontend/router-tabs-introduction.md +26 -3
  124. package/cabloy-docs/frontend/router-tabs-layout-integration.md +367 -0
  125. package/cabloy-docs/frontend/router-tabs-mechanism.md +6 -0
  126. package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +7 -0
  127. package/cabloy-docs/frontend/router-tabs-vs-stack.md +167 -0
  128. package/cabloy-docs/frontend/router-view-hosts-guide.md +450 -0
  129. package/cabloy-docs/frontend/server-data.md +4 -1
  130. package/cabloy-docs/frontend/system-startup-guide.md +2 -2
  131. package/cabloy-docs/frontend/table-action-visibility-permission-flow-guide.md +263 -0
  132. package/cabloy-docs/frontend/table-cell-cookbook.md +568 -0
  133. package/cabloy-docs/frontend/table-guide.md +373 -0
  134. package/cabloy-docs/frontend/table-resource-crud-cookbook.md +496 -0
  135. package/cabloy-docs/frontend/zova-app-guide.md +251 -0
  136. package/cabloy-docs/frontend/zova-form-source-reading-map.md +293 -0
  137. package/cabloy-docs/frontend/zova-form-under-the-hood.md +561 -0
  138. package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
  139. package/cabloy-docs/frontend/zova-router-under-the-hood.md +561 -0
  140. package/cabloy-docs/frontend/zova-source-reading-map.md +421 -0
  141. package/cabloy-docs/frontend/zova-table-controller-render-supplement.md +225 -0
  142. package/cabloy-docs/frontend/zova-table-source-reading-map.md +317 -0
  143. package/cabloy-docs/frontend/zova-table-under-the-hood.md +532 -0
  144. package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
  145. package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist.md +245 -0
  146. package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map.md +139 -0
  147. package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook.md +248 -0
  148. package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions.md +511 -0
  149. package/cabloy-docs/fullstack/contract-loop-playbook.md +356 -0
  150. package/cabloy-docs/fullstack/edition-collaboration-differences.md +6 -0
  151. package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +199 -23
  152. package/cabloy-docs/fullstack/introduction.md +15 -1
  153. package/cabloy-docs/fullstack/openapi-to-sdk.md +135 -11
  154. package/cabloy-docs/fullstack/suites-and-modules.md +333 -0
  155. package/cabloy-docs/fullstack/tutorial-1-first-module.md +3 -0
  156. package/cabloy-docs/fullstack/tutorial-2-first-crud.md +4 -0
  157. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +6 -2
  158. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +60 -23
  159. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +14 -7
  160. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +6 -0
  161. package/cabloy-docs/fullstack/tutorials-overview.md +17 -4
  162. package/cabloy-docs/reference/bean-scene-boilerplates.md +15 -13
  163. package/cabloy-docs/reference/package-map.md +4 -3
  164. package/package.json +2 -1
  165. package/scripts/init.ts +2 -18
  166. package/scripts/initTestData.ts +25 -0
  167. package/scripts/upgrade.ts +17 -2
  168. package/vona/pnpm-lock.yaml +48 -194
  169. package/vona/src/suite/a-training/modules/training-student/package.json +53 -0
  170. package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +400 -0
  171. package/vona/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +18 -0
  172. package/vona/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
  173. package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +12 -0
  174. package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +21 -0
  175. package/vona/src/suite/a-training/modules/training-student/src/bean/ssrMenu.student.ts +29 -0
  176. package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +15 -0
  177. package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +15 -0
  178. package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +74 -0
  179. package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +28 -0
  180. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectReq.tsx +44 -0
  181. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectRes.tsx +11 -0
  182. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +45 -0
  183. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +42 -0
  184. package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +28 -0
  185. package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +25 -0
  186. package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +84 -0
  187. package/vona/src/suite/a-training/modules/training-student/src/index.ts +2 -0
  188. package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +10 -0
  189. package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +57 -0
  190. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +173 -0
  191. package/vona/src/suite/a-training/modules/training-student/tsconfig.build.json +11 -0
  192. package/vona/src/suite/a-training/modules/training-student/tsconfig.json +7 -0
  193. package/vona/src/suite/a-training/package.json +12 -0
  194. package/vona/src/suite/a-training/tsconfig.base.json +4 -0
  195. package/vona/src/suite/a-training/tsconfig.json +10 -0
  196. package/zova/packages-cli/cli/package.json +2 -2
  197. package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
  198. package/zova/packages-cli/cli-set-front/package.json +1 -1
  199. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
  200. package/zova/packages-zova/zova/package.json +2 -2
  201. package/zova/pnpm-lock.yaml +416 -690
  202. package/zova/src/suite/a-training/modules/training-student/cli/openapi.config.ts +9 -0
  203. package/zova/src/suite/a-training/modules/training-student/package.json +52 -0
  204. package/zova/src/suite/a-training/modules/training-student/src/.metadata/component/formFieldLevel.ts +31 -0
  205. package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +258 -0
  206. package/zova/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +7 -0
  207. package/zova/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
  208. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/baseURL.ts +5 -0
  209. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/index.ts +3 -0
  210. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +196 -0
  211. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +4146 -0
  212. package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +151 -0
  213. package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +43 -0
  214. package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionDeleteForce.tsx +51 -0
  215. package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +56 -0
  216. package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.level.tsx +63 -0
  217. package/zova/src/suite/a-training/modules/training-student/src/component/formFieldLevel/controller.tsx +117 -0
  218. package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
  219. package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
  220. package/zova/src/suite/a-training/modules/training-student/src/index.ts +2 -0
  221. package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +42 -0
  222. package/zova/src/suite/a-training/modules/training-student/tsconfig.build.json +13 -0
  223. package/zova/src/suite/a-training/modules/training-student/tsconfig.json +5 -0
  224. package/zova/src/suite/a-training/package.json +12 -0
  225. package/zova/src/suite/a-training/tsconfig.base.json +4 -0
  226. package/zova/src/suite/a-training/tsconfig.json +4 -0
  227. package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +29 -7
  228. package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/select/controller.tsx +34 -11
  229. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  230. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +3 -3
  231. package/zova/src/suite-vendor/a-zova/modules/a-table/src/lib/tableCell.ts +1 -1
  232. package/zova/src/suite-vendor/a-zova/package.json +2 -2
@@ -2,11 +2,21 @@
2
2
 
3
3
  <Badge type="info" text="Basic" />
4
4
 
5
- In this tutorial, one prompt lets AI upgrade the `level` field from built-in render resources to custom frontend renderers owned by the `demo-student` module.
5
+ In this tutorial, one prompt lets the user express a simple product need: the `level` field in the Student experience should feel less generic and more like a real training-stage workflow.
6
+
7
+ From that user need, AI can infer that the next step is no longer just relabeling the field. It now needs a more dedicated rendering experience owned by the `demo-student` module.
8
+
9
+ This tutorial covers the **reverse chain** custom-resource handoff branch of the contract loop.
10
+
11
+ > [!NOTE]
12
+ > Like the earlier tutorials in this series, this page keeps using the standalone `demo-student` sandbox.
13
+ > That keeps the custom-renderer experiment isolated from the repo's real suite-owned `a-training/training-student` implementation.
6
14
 
7
15
  ## Goal
8
16
 
9
- By the end of this tutorial, you will understand:
17
+ By the end of this tutorial, you will understand how a user-facing request about a more business-specific `level` experience turns into a concrete custom-renderer implementation.
18
+
19
+ In particular, you will understand:
10
20
 
11
21
  - when built-in render metadata is enough and when a custom renderer is worth adding
12
22
  - how a frontend table cell bean and a frontend form-field component can both serve the same backend field
@@ -17,17 +27,17 @@ By the end of this tutorial, you will understand:
17
27
  Give AI a prompt like this:
18
28
 
19
29
  ```text
20
- Please make the level UI more business-specific in the Student list page and form.
30
+ For demo purposes, use custom renderer components to give the `level` field on the Student list page and form a more distinctive look and feel.
21
31
  ```
22
32
 
23
33
  ## Why this step matters
24
34
 
25
- This is the right follow-up step because built-in render resources are a good starting point, but some business fields eventually need module-specific behavior.
35
+ This is the right follow-up step because built-in render resources are a good starting point, but some fields eventually need a more distinctive user experience to match the business workflow.
26
36
 
27
- The `level` field is a good teaching example because this step deepens the UI in two concrete ways:
37
+ The `level` field is a good teaching example because users often expect two improvements once a training workflow becomes more realistic:
28
38
 
29
- - a custom table cell that renders a more business-specific badge style
30
- - a custom form field that adds helper text, readonly behavior, or module-specific select styling
39
+ - the list should make each training stage easier to recognize at a glance
40
+ - the form should guide the user more clearly when choosing a training stage
31
41
 
32
42
  This is where Cabloy’s contract model becomes more practical: the backend field still owns the business contract, while the frontend module progressively deepens the UI behavior behind that contract.
33
43
 
@@ -50,14 +60,15 @@ npm run zova :create:component formFieldLevel -- --module=demo-student
50
60
 
51
61
  Usage notes:
52
62
 
53
- - use `:create:bean` when you need a table-cell render resource under the bean scene
54
- - use `:create:component` when you need a custom frontend component/controller surface
63
+ - use `:create:bean` when AI determines that the list needs a dedicated table-cell render resource under the bean scene
64
+ - use `:create:component` when AI determines that the form needs a custom frontend component/controller surface
55
65
  - generation gives you the structural starting point, but this tutorial still expects manual refinement so the result matches the `demo-student` teaching implementation
56
66
  - after frontend resources exist, return to the backend entity and point `ZovaRender.field(...)` and `ZovaRender.cell(...)` at the custom module resources
67
+ - once backend metadata starts consuming those new frontend resources, treat the next step as a reverse fullstack handoff rather than frontend-only cleanup: refresh generated output, rebuild the relevant flavor, and re-sync Vona dependencies
57
68
 
58
69
  ## Generated or affected files
59
70
 
60
- By the end of this tutorial, your module should provide these teaching anchors:
71
+ To satisfy the user-facing need above, AI will usually converge on a small set of implementation anchors like these:
61
72
 
62
73
  - custom table cell bean:
63
74
  - `zova/src/module/demo-student/src/bean/tableCell.level.tsx`
@@ -68,50 +79,76 @@ By the end of this tutorial, your module should provide these teaching anchors:
68
79
  - backend field contract to update:
69
80
  - `vona/src/module/demo-student/src/entity/student.tsx`
70
81
 
71
- Representative custom metadata targets are:
82
+ Representative metadata targets after AI makes that implementation decision are:
72
83
 
73
84
  ```typescript
74
85
  ZovaRender.field('demo-student:formFieldLevel', {
75
86
  items: levelItems,
76
87
  helper: $locale('LevelPlaceholder'),
77
- })
88
+ });
78
89
  ```
79
90
 
80
91
  and:
81
92
 
82
93
  ```typescript
83
- ZovaRender.cell('demo-student:level', { items: levelItems })
94
+ ZovaRender.cell('demo-student:level', { items: levelItems });
84
95
  ```
85
96
 
86
- ## What those files mean in the business thread
97
+ This is the point where a user request about “better list presentation” and “better form guidance” starts turning into explicit renderer resources and backend metadata links.
98
+
99
+ ## How those files support the user experience
87
100
 
88
- This tutorial makes the split of responsibilities explicit:
101
+ These files work together to deliver the richer `level` experience:
89
102
 
90
- - `tableCell.level.tsx` owns the custom table-cell rendering behavior for `level`
91
- - `component/formFieldLevel/controller.tsx` owns the custom form-field behavior for `level`
103
+ - `tableCell.level.tsx` makes the training stage easier to recognize in the list
104
+ - `component/formFieldLevel/controller.tsx` makes the form interaction more guided and business-specific
92
105
  - `.metadata/component/formFieldLevel.ts` exposes that component through the module registration surface
93
106
  - `entity/student.tsx` remains the backend-owned business contract that chooses which frontend resources should render the field
94
107
 
95
- That means the backend still defines the business field, validation, and metadata entry point, while the frontend module owns the implementation details of the richer UI behavior.
108
+ That means the backend still defines the business field, validation, and metadata entry point, while the frontend module owns the implementation details that make the experience feel more tailored to the Student Training Center workflow.
96
109
 
97
110
  ## Verification
98
111
 
99
- 1. make sure the local dev workflow is running:
112
+ These checks are the reverse-chain synchronization steps AI must complete so the user-facing renderer change is actually available to backend consumers and the running app.
113
+
114
+ 1. refresh the generated handoff surfaces before checking backend consumers:
115
+
116
+ ```bash
117
+ npm run zova :tools:metadata demo-student
118
+ npm run build:zova:admin
119
+ npm run deps:vona
120
+ ```
121
+
122
+ If the same renderer path must also be available for Web, also run:
123
+
124
+ ```bash
125
+ npm run build:zova:web
126
+ npm run deps:vona
127
+ ```
128
+
129
+ If backend-side type consumers still cannot see the new shared renderer types even though generated `.zova-rest` output is already correct, rebuild `vona/node_modules` and reinstall dependencies:
130
+
131
+ ```bash
132
+ cd vona && rm -rf node_modules && pnpm install
133
+ ```
134
+
135
+ 2. make sure the local dev workflow is running:
100
136
 
101
137
  ```bash
102
138
  npm run dev
103
139
  ```
104
140
 
105
- 2. open `http://localhost:7102/admin/`
106
- 3. enter the **Student** list page and verify that the `level` column now uses the custom table-cell presentation
107
- 4. open a Student create, update, or view form and verify that the `level` field now uses the custom form-field behavior
108
- 5. inspect `vona/src/module/demo-student/src/entity/student.tsx` and confirm that the backend metadata now points to `demo-student:formFieldLevel` and `demo-student:level`
141
+ 3. open `http://localhost:7102/admin/`
142
+ 4. enter the **Student** list page and verify that the `level` column now uses the custom table-cell presentation
143
+ 5. open a Student create, update, or view form and verify that the `level` field now uses the custom form-field behavior
144
+ 6. inspect `vona/src/module/demo-student/src/entity/student.tsx` and confirm that the backend metadata now points to `demo-student:formFieldLevel` and `demo-student:level`
109
145
 
110
146
  ## Read more
111
147
 
112
148
  - [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
113
149
  - [Frontend CLI](/frontend/cli)
114
150
  - [Component Guide](/frontend/component-guide)
151
+ - [Zova Form Under the Hood](/frontend/zova-form-under-the-hood)
115
152
  - [Bean Scene Boilerplate Variants](/reference/bean-scene-boilerplates)
116
153
 
117
154
  ## Next step
@@ -2,20 +2,25 @@
2
2
 
3
3
  <Badge type="info" text="Basic" />
4
4
 
5
- In this tutorial, one prompt lets AI show the forward direction of Cabloy’s fullstack contract loop: backend API contracts that generate and refresh the frontend consumption surface.
5
+ In this tutorial, one prompt lets AI show the **forward chain** of Cabloy’s fullstack contract loop: backend API contracts that generate and refresh the frontend consumption surface.
6
6
 
7
7
  The teaching thread in this page is the pair of Student actions:
8
8
 
9
9
  - `summary/:id`
10
10
  - `deleteForce/:id`
11
11
 
12
+ > [!NOTE]
13
+ > This tutorial still runs inside the standalone `demo-student` sandbox from the earlier pages.
14
+ > Use that sandbox for OpenAPI regeneration experiments so you do not interfere with the repo's real suite-owned `a-training/training-student` implementation.
15
+
12
16
  ## Goal
13
17
 
14
18
  By the end of this tutorial, you will understand:
15
19
 
16
20
  - how a backend controller and DTO change becomes frontend generated API output
17
21
  - how backend row-action metadata can drive frontend table actions
18
- - how generated API, frontend model helpers, and row-action beans fit into one contract-sharing workflow
22
+ - how generated API, thin frontend model helpers, and row-action beans fit into one forward-chain workflow
23
+ - why custom resource endpoints that still belong to the same resource should reuse the existing resource-owner instead of creating a competing cache owner
19
24
 
20
25
  ## AI Prompt
21
26
 
@@ -26,8 +31,6 @@ Please add two custom actions to the Student list:
26
31
 
27
32
  - Summary: return or display a student summary for the selected row
28
33
  - Force Delete: permanently delete the selected student through a dedicated row action
29
-
30
- Make both actions work end to end, from the backend contract to the Student list page.
31
34
  ```
32
35
 
33
36
  ## Why this step matters
@@ -60,6 +63,8 @@ Usage notes:
60
63
  - use the backend controller and DTOs as the starting point
61
64
  - inspect the module OpenAPI config before generation
62
65
  - prefer regeneration over hand-written duplicate API layers when the module already owns an OpenAPI contract surface
66
+ - keep frontend follow-up thin: treat the module model as a semantic facade over generated API consumers rather than a second contract-definition layer
67
+ - if the custom endpoint still belongs to the existing resource, reuse the existing resource-owner for server-state ownership
63
68
 
64
69
  ## Generated or affected files
65
70
 
@@ -105,10 +110,11 @@ This tutorial is easiest to understand as one contract chain:
105
110
  3. `dto/studentSelectResItem.tsx` defines the row-action metadata that exposes those actions in the Student list page
106
111
  4. `cli/openapi.config.ts` tells the frontend module which backend operations it owns
107
112
  5. `src/api/demoStudent.ts` is the generated typed API surface created from that backend contract
108
- 6. `src/model/student.ts` wraps the generated API in frontend business-facing helper methods
109
- 7. `tableCell.actionSummary.tsx` and `tableCell.actionDeleteForce.tsx` turn those model methods into visible row actions
113
+ 6. `src/model/student.ts` wraps the generated API in a thin frontend semantic facade
114
+ 7. the model should reuse the existing resource-owner for server-state ownership when the new API still belongs to the Student resource
115
+ 8. `tableCell.actionSummary.tsx` and `tableCell.actionDeleteForce.tsx` turn those model methods into visible row actions
110
116
 
111
- That is the practical contract-sharing loop: backend controller and DTO truth flows into generated frontend API output, then into frontend model helpers, and finally into visible table actions.
117
+ That is the practical forward chain: backend controller and DTO truth flows into generated frontend API output, then into thin frontend model helpers, and finally into visible table actions.
112
118
 
113
119
  ## Verification
114
120
 
@@ -133,6 +139,7 @@ npm run dev
133
139
 
134
140
  ## Read more
135
141
 
142
+ - [Backend Metadata to Frontend Table Actions](/fullstack/backend-metadata-to-frontend-table-actions)
136
143
  - [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
137
144
  - [OpenAPI Guide](/backend/openapi-guide)
138
145
  - [OpenAPI SDK Guide](/frontend/openapi-sdk-guide)
@@ -4,8 +4,14 @@
4
4
 
5
5
  In this tutorial, one prompt lets AI close the series by showing Cabloy’s core fullstack idea: one field-oriented contract surface can drive several behaviors across backend and frontend.
6
6
 
7
+ This capstone sits on top of both the forward chain and the reverse chain rather than replacing either one.
8
+
7
9
  This time the main teaching field is `mobile`, while `level` stays as the supporting example for table and form rendering.
8
10
 
11
+ > [!NOTE]
12
+ > This capstone still uses the standalone `demo-student` sandbox carried through the tutorial series.
13
+ > That keeps the final experiment path isolated while preserving a clean comparison against the repo's real suite-owned `a-training/training-student` implementation.
14
+
9
15
  ## Goal
10
16
 
11
17
  By the end of this tutorial, you will understand how one business field thread can participate in:
@@ -36,7 +36,7 @@ Why these fields?
36
36
 
37
37
  This keeps the storyline small enough for beginners while still showing Cabloy’s fullstack contract model.
38
38
 
39
- At the beginning of the series, the `demo-student` module does not exist yet. The tutorials build it step by step.
39
+ At the beginning of the series, the `demo-student` module does not exist yet. The tutorials build it step by step. This standalone tutorial track is intentional: it gives readers a safe experiment surface that does not collide with the repo's real `a-training/training-student` implementation and also makes side-by-side comparison easier.
40
40
 
41
41
  ## What you should prepare first
42
42
 
@@ -61,16 +61,29 @@ Those pages explain the repo entrypoints and the CLI-first workflow model that t
61
61
  - [Tutorial 1: Create Your First Module](/fullstack/tutorial-1-first-module)
62
62
  - [Tutorial 2: Create Your First CRUD](/fullstack/tutorial-2-first-crud)
63
63
 
64
- ### Phase 2: Share frontend rendering metadata through the backend contract
64
+ ### Phase 2: Reverse chain — share frontend rendering metadata through the backend contract
65
65
 
66
66
  - [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing)
67
67
  - [Tutorial 4: Custom Form/Table Renderers for Level](/fullstack/tutorial-4-custom-level-renderers)
68
68
 
69
- ### Phase 3: Share backend contracts forward into frontend consumption
69
+ Important handoff note for this phase:
70
+
71
+ - this phase teaches the **reverse chain** of the Cabloy contract loop
72
+ - Tutorial 3 uses the built-in metadata branch
73
+ - Tutorial 4 uses the custom resource handoff branch
74
+ - once a frontend resource created in these tutorials is later consumed by backend metadata, do not stop at frontend source edits alone
75
+ - refresh the generated frontend output, run the relevant flavor build, then run `npm run deps:vona`
76
+ - if backend-side shared types still look stale after that normal sync flow, rebuild `vona/node_modules` and reinstall dependencies
77
+
78
+ See [Contract Loop Playbook](/fullstack/contract-loop-playbook) and [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend) for the full reverse-chain explanation.
79
+
80
+ ### Phase 3: Forward chain — share backend contracts into frontend consumption
70
81
 
71
82
  - [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing)
72
83
 
73
- ### Phase 4: Understand one contract surface through one field story
84
+ This phase teaches the **forward chain** of the contract loop: backend contract truth changes first, generated frontend consumers are refreshed second, and frontend follow-up stays thin and resource-owner-aware.
85
+
86
+ ### Phase 4: One field story across multiple contract surfaces
74
87
 
75
88
  - [Tutorial 6: One Contract Surface, Four Uses](/fullstack/tutorial-6-one-contract-four-uses)
76
89
 
@@ -28,15 +28,15 @@ A practical contributor rule is:
28
28
 
29
29
  ### Current built-in scenes with variants
30
30
 
31
- | Scene | Default metadata key | Named variant keys | Example command | Source module |
32
- | -------------- | -------------------- | ------------------- | --------------------------------------------------------------------------------------------- | ---------------------- |
33
- | `filter` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean filter log -- --module=demo-student --boilerplate=global` | `vona-module-a-aspect` |
34
- | `pipe` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean pipe log -- --module=demo-student --boilerplate=global` | `vona-module-a-aspect` |
35
- | `interceptor` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean interceptor log -- --module=demo-student --boilerplate=global` | `vona-module-a-aspect` |
36
- | `guard` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean guard auth -- --module=demo-student --boilerplate=global` | `vona-module-a-aspect` |
37
- | `middleware` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean middleware trace -- --module=demo-student --boilerplate=global` | `vona-module-a-aspect` |
38
- | `ssrMenu` | `boilerplate` | `boilerplateWeb` | `npm run vona :create:bean ssrMenu menuTest -- --module=demo-student --boilerplate=web` | `vona-module-a-ssr` |
39
- | `ssrMenuGroup` | `boilerplate` | `boilerplateWeb` | `npm run vona :create:bean ssrMenuGroup groupTest -- --module=demo-student --boilerplate=web` | `vona-module-a-ssr` |
31
+ | Scene | Default metadata key | Named variant keys | Example command | Source module |
32
+ | -------------- | -------------------- | ------------------- | ------------------------------------------------------------------------------------------------- | ---------------------- |
33
+ | `filter` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean filter log -- --module=training-student --boilerplate=global` | `vona-module-a-aspect` |
34
+ | `pipe` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean pipe log -- --module=training-student --boilerplate=global` | `vona-module-a-aspect` |
35
+ | `interceptor` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean interceptor log -- --module=training-student --boilerplate=global` | `vona-module-a-aspect` |
36
+ | `guard` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean guard auth -- --module=training-student --boilerplate=global` | `vona-module-a-aspect` |
37
+ | `middleware` | `boilerplate` | `boilerplateGlobal` | `npm run vona :create:bean middleware trace -- --module=training-student --boilerplate=global` | `vona-module-a-aspect` |
38
+ | `ssrMenu` | `boilerplate` | `boilerplateWeb` | `npm run vona :create:bean ssrMenu menuTest -- --module=training-student --boilerplate=web` | `vona-module-a-ssr` |
39
+ | `ssrMenuGroup` | `boilerplate` | `boilerplateWeb` | `npm run vona :create:bean ssrMenuGroup groupTest -- --module=training-student --boilerplate=web` | `vona-module-a-ssr` |
40
40
 
41
41
  These backend entries come from the current `vonaModule.onions` metadata in `a-aspect` and `a-ssr`.
42
42
 
@@ -44,13 +44,15 @@ These backend entries come from the current `vonaModule.onions` metadata in `a-a
44
44
 
45
45
  ### Current built-in scenes with variants
46
46
 
47
- | Scene | Default metadata key | Named variant keys | Example command pattern | Source module |
48
- | ----------- | -------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------- |
49
- | `command` | `boilerplate` | `boilerplateCommandBulk`, `boilerplateCommandRow` | `npm run zova :create:bean command test -- --module=demo-student --boilerplate=commandRow` | `zova-module-a-command` |
50
- | `tableCell` | `boilerplate` | `boilerplateTableActionRow` | `npm run zova :create:bean tableCell test -- --module=demo-student --boilerplate=tableActionRow` | `zova-module-a-table` |
47
+ | Scene | Default metadata key | Named variant keys | Example command pattern | Source module |
48
+ | ----------- | -------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------- |
49
+ | `command` | `boilerplate` | `boilerplateCommandBulk`, `boilerplateCommandRow` | `npm run zova :create:bean command test -- --module=training-student --boilerplate=commandRow` | `zova-module-a-command` |
50
+ | `tableCell` | `boilerplate` | `boilerplateTableActionRow` | `npm run zova :create:bean tableCell test -- --module=training-student --boilerplate=tableActionRow` | `zova-module-a-table` |
51
51
 
52
52
  These frontend entries come from the current `zovaModule.onions` metadata in `a-command` and `a-table`.
53
53
 
54
+ For the built-in command scene’s runtime model and helper-base patterns, see [Command Scene Authoring](/frontend/command-scene-authoring).
55
+
54
56
  ## Guidance for AI-assisted development
55
57
 
56
58
  Do not assume every bean scene supports named variants.
@@ -32,10 +32,10 @@ Representative package metadata in the current repo shows the distinction clearl
32
32
 
33
33
  ### Module package
34
34
 
35
- Example: `vona/src/module/demo-student/package.json`
35
+ Example: `vona/src/suite/a-training/modules/training-student/package.json`
36
36
 
37
- - package name: `vona-module-demo-student`
38
- - title: `demo-student`
37
+ - package name: `vona-module-training-student`
38
+ - title: `training-student`
39
39
  - `vonaModule.dependencies` records module-level framework dependencies
40
40
 
41
41
  ### Suite package
@@ -74,6 +74,7 @@ A practical comparison is:
74
74
 
75
75
  Use this package map together with:
76
76
 
77
+ - [Suites and Modules](/fullstack/suites-and-modules)
77
78
  - [Backend Essentials](/backend/backend-essentials)
78
79
  - [Backend Foundation](/backend/foundation)
79
80
  - [Backend CLI](/backend/cli)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.60",
3
+ "version": "5.1.62",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -22,6 +22,7 @@
22
22
  "type": "module",
23
23
  "scripts": {
24
24
  "init": "node scripts/init.ts",
25
+ "init:test-data": "node scripts/initTestData.ts",
25
26
  "upgrade": "node scripts/upgrade.ts",
26
27
  "upgrade:dry-run": "node scripts/upgrade.ts --dry-run",
27
28
  "vona": "node ./vona/packages-cli/cli/src/bin/vona.ts --projectPath=vona",
package/scripts/init.ts CHANGED
@@ -247,22 +247,7 @@ function buildSsrCabloyBasicStartBatch(): void {
247
247
  }
248
248
  }
249
249
 
250
- // --- Step F: initTestData ---
251
-
252
- function initTestData(): void {
253
- // eslint-disable-next-line
254
- console.log('[init] Initializing test data via npm run test...');
255
- try {
256
- exec('npm run test');
257
- } catch {
258
- // eslint-disable-next-line
259
- console.warn(
260
- '[init] npm run test failed after init completed; Redis may be unavailable, skipping test data initialization',
261
- );
262
- }
263
- }
264
-
265
- // --- Step G: cleanupWorkspaceYaml ---
250
+ // --- Step F: cleanupWorkspaceYaml ---
266
251
 
267
252
  function cleanupWorkspaceYaml(): void {
268
253
  const subProjects = ['vona', 'zova'];
@@ -283,7 +268,7 @@ function cleanupWorkspaceYaml(): void {
283
268
  }
284
269
  }
285
270
 
286
- // --- Step H: init:cabloy-docs ---
271
+ // --- Step G: init:cabloy-docs ---
287
272
 
288
273
  function initCabloyDocs(): void {
289
274
  const pkgPath = resolve(CABLOY_DOCS_DIR, 'package.json');
@@ -306,6 +291,5 @@ initZova();
306
291
  initCabloyDocs();
307
292
  buildSsrCabloyBasicStartBatch();
308
293
  writeVersionMarker();
309
- initTestData();
310
294
  // eslint-disable-next-line
311
295
  console.log('[init] Done!');
@@ -0,0 +1,25 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const ROOT_DIR = resolve(__dirname, '..');
7
+
8
+ function exec(cmd: string): void {
9
+ execSync(cmd, { stdio: 'inherit', cwd: ROOT_DIR });
10
+ }
11
+
12
+ function initTestData(): void {
13
+ // eslint-disable-next-line no-console
14
+ console.log('[init:test-data] Initializing test data via npm run test...');
15
+ try {
16
+ exec('npm run test');
17
+ } catch {
18
+ // eslint-disable-next-line no-console
19
+ console.warn(
20
+ '[init:test-data] npm run test failed after init completed; Redis may be unavailable, skipping test data initialization',
21
+ );
22
+ }
23
+ }
24
+
25
+ initTestData();
@@ -300,7 +300,17 @@ function runInit(dryRun: boolean, version: string): void {
300
300
  exec('npm run init', { CABLOY_VERSION: version } as any);
301
301
  }
302
302
 
303
- // --- Step 5: Cleanup ---
303
+ // --- Step 5: Run init:test-data ---
304
+
305
+ function runInitTestData(dryRun: boolean): void {
306
+ if (dryRun) {
307
+ log(' [dry-run] Run: npm run init:test-data');
308
+ return;
309
+ }
310
+ exec('npm run init:test-data');
311
+ }
312
+
313
+ // --- Step 6: Cleanup ---
304
314
 
305
315
  function cleanup(dryRun?: boolean): void {
306
316
  if (dryRun) {
@@ -366,6 +376,11 @@ async function main(): Promise<void> {
366
376
  runInit(dryRun, latestPackageInfo.version);
367
377
  log('');
368
378
 
379
+ // 5. Run init:test-data
380
+ log('Running npm run init:test-data...');
381
+ runInitTestData(dryRun);
382
+ log('');
383
+
369
384
  if (dryRun) {
370
385
  log(`[dry-run] Current Cabloy version would become: ${latestPackageInfo.version}`);
371
386
  } else {
@@ -374,7 +389,7 @@ async function main(): Promise<void> {
374
389
 
375
390
  log('Upgrade complete!');
376
391
  } finally {
377
- // 5. Cleanup
392
+ // 6. Cleanup
378
393
  cleanup(dryRun);
379
394
  }
380
395
  }