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
@@ -0,0 +1,334 @@
1
+ # Using `ModelResource` in Your Module
2
+
3
+ This guide explains the two recommended ways to use `ModelResource` in application code.
4
+
5
+ It is the practical follow-up to [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern).
6
+
7
+ For review guardrails and design checks after applying the pattern, continue with [Resource Model Best Practices and Anti-Patterns](/frontend/model-resource-best-practices).
8
+
9
+ If you need the lower-level generic model runtime beneath this resource-owner usage layer, continue with [Model Runtime Under the Hood](/frontend/a-model-under-the-hood).
10
+
11
+ For implementation templates covering common extension scenarios, continue with [Resource Model Cookbook](/frontend/model-resource-cookbook).
12
+
13
+ > [!TIP]
14
+ > **Resource docs path**
15
+ >
16
+ > 1. **[Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)** — learn why `ModelResource` is a resource owner
17
+ > 2. **[Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood)** — learn how the module runtime pieces cooperate
18
+ > 3. **[Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map)** — learn which files to read next
19
+ > 4. **[Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide)** — learn how to reuse the owner in application code
20
+ > 5. **[Resource Model Best Practices](/frontend/model-resource-best-practices)** — learn the review guardrails
21
+ > 6. **[Resource Model Cookbook](/frontend/model-resource-cookbook)** — learn the common implementation shapes
22
+ >
23
+ > **You are here:** step 4.
24
+ > **Previous recommended pages:** [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern), [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood), and [Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map).
25
+ > **Next recommended pages:** [Resource Model Best Practices](/frontend/model-resource-best-practices), then [Resource Model Cookbook](/frontend/model-resource-cookbook).
26
+
27
+ Use this page when the main question is not only “what does `ModelResource` do?”, but also:
28
+
29
+ - when should I use it directly?
30
+ - when should I add a thin business facade?
31
+ - which responsibilities should remain in the existing resource-owner?
32
+ - where should custom business logic live?
33
+
34
+ ## Why this page exists
35
+
36
+ After reading the `rest-resource` source, the next practical step is usually application.
37
+
38
+ A frontend developer often needs one of these outcomes:
39
+
40
+ 1. use `ModelResource` directly
41
+ 2. add a thin business facade over the existing resource-owner
42
+
43
+ This page explains those two choices.
44
+
45
+ ## The base specimen
46
+
47
+ The base resource-owner model is:
48
+
49
+ - `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts`
50
+
51
+ Representative consumers that use it through selector-based lookup include:
52
+
53
+ - `zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx`
54
+ - `zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx`
55
+
56
+ Those consumers are important because they show that UI blocks can depend on the resource-owner contract without needing to know the low-level resource logic.
57
+
58
+ ## The first decision: use directly or add a thin facade?
59
+
60
+ A practical decision rule is:
61
+
62
+ ### Use `ModelResource` directly when
63
+
64
+ - the resource is close to standard CRUD
65
+ - default `select` / `view` / `create` / `update` / `delete` behavior is already enough
66
+ - form schema and permission ownership can follow the generic resource path
67
+ - generic blocks can consume the resource-owner surface as-is
68
+ - you mainly want the existing resource-owner facade without extra business semantics
69
+
70
+ ### Add a thin facade over the existing resource-owner when
71
+
72
+ - the resource cache owner already exists through `rest-resource`
73
+ - the business module needs a semantic frontend surface such as `summary(...)`, `selectArchived(...)`, or `deleteForce(...)`
74
+ - you want to follow Cabloy’s bidirectional contract loop **forward chain**
75
+ - the right frontend move is to reuse the existing resource-owner instead of creating a competing cache owner
76
+
77
+ In that case, a thin business model facade is often better than creating a second resource-level state owner.
78
+
79
+ The key point is that the business model does **not** become the cache owner itself.
80
+
81
+ Instead, it delegates row/list/mutation ownership to the existing `ModelResource` instance.
82
+
83
+ ## The key architectural rule
84
+
85
+ The goal is usually **not** to create another resource-owner surface for the same resource.
86
+
87
+ The goal is to keep one stable owner boundary and add business-specific semantics on top of it only when needed.
88
+
89
+ A good mental model is:
90
+
91
+ - `ModelResource` owns the generic resource contract
92
+ - your business-facing model owns semantic convenience methods only when the UI needs them
93
+
94
+ ## Pattern 1: use `ModelResource` directly
95
+
96
+ This is the cleanest option when the generic resource owner already matches the real business shape.
97
+
98
+ Typical signs:
99
+
100
+ - the resource mostly needs standard CRUD
101
+ - generic pages or forms already work well
102
+ - no extra semantic query or mutation surface is needed yet
103
+ - the team benefits more from uniformity than from additional business naming
104
+
105
+ In this mode, the best abstraction is often no extra abstraction.
106
+
107
+ ## Pattern 2: add a thin business facade over the existing resource-owner
108
+
109
+ This is the right option when business semantics appear, but ownership should stay centralized in the existing resource-owner.
110
+
111
+ A representative shape is:
112
+
113
+ ```typescript
114
+ const StudentResource = 'training-student:student';
115
+
116
+ @Model()
117
+ export class ModelStudent extends BeanModelBase {
118
+ @Use({ beanFullName: 'rest-resource.model.resource' })
119
+ protected get $$modelResource(): ModelResource {
120
+ return usePrepareArg(StudentResource, true);
121
+ }
122
+
123
+ summary(id: TableIdentity) {
124
+ return this.$$modelResource.queryItem({
125
+ id,
126
+ action: 'summary',
127
+ queryFn: async () => {
128
+ const res = await this.scope.api.trainingStudent.summary({ params: { id } });
129
+ return res ?? null;
130
+ },
131
+ meta: {
132
+ disableSuspenseOnInit: true,
133
+ },
134
+ });
135
+ }
136
+
137
+ deleteForce(id: TableIdentity) {
138
+ return this.$$modelResource.mutationItem<void, void>({
139
+ id,
140
+ action: 'deleteForce',
141
+ mutationFn: async () => {
142
+ await this.scope.api.trainingStudent.deleteForce({ params: { id } });
143
+ },
144
+ });
145
+ }
146
+ }
147
+ ```
148
+
149
+ What this pattern preserves:
150
+
151
+ - one cache owner
152
+ - one selector-based resource identity model
153
+ - one list/item invalidation policy
154
+ - one resource-level state boundary
155
+
156
+ What this pattern adds:
157
+
158
+ - semantic business-facing methods
159
+ - better UI readability
160
+ - a cleaner place for forward-chain frontend follow-up
161
+
162
+ ## What should remain owned by `ModelResource`
163
+
164
+ In both usage modes, these parts should remain conceptually owned by the existing resource-owner pattern:
165
+
166
+ - resource bootstrap
167
+ - `resourceApi` resolution
168
+ - select/view/create/update/delete conventions
169
+ - form schema resolution
170
+ - permission/schema/form-provider surfaces
171
+ - generic list/item invalidation structure
172
+
173
+ That does not mean you can never customize behavior.
174
+
175
+ It means the customization should still reuse the same owner boundary instead of competing with it.
176
+
177
+ ## The safest extension points
178
+
179
+ The safest extension points are usually **new business-facing methods** that delegate to the existing resource-owner helper surfaces.
180
+
181
+ Typical examples:
182
+
183
+ - additional item queries through `queryItem(...)`
184
+ - additional list queries through `selectGeneral(...)`
185
+ - business actions through `mutationItem(...)`
186
+ - resource-specific computed helpers
187
+ - schema or permission convenience helpers
188
+
189
+ This keeps the generic resource contract intact while adding local business semantics.
190
+
191
+ ## Pattern 3: add a row-level custom query through the facade
192
+
193
+ Use this when the resource has a domain-specific query that is not just `select` or `view`.
194
+
195
+ Representative shape:
196
+
197
+ ```typescript
198
+ summary(id: TableIdentity) {
199
+ return this.$$modelResource.queryItem({
200
+ id,
201
+ action: 'summary',
202
+ queryFn: async () => {
203
+ const res = await this.scope.api.trainingStudent.summary({ params: { id } });
204
+ return res ?? null;
205
+ },
206
+ });
207
+ }
208
+ ```
209
+
210
+ Why this is a good pattern:
211
+
212
+ - it reuses `queryItem(...)`
213
+ - it stays under the existing resource-owner cache-key structure
214
+ - it keeps row-level query ownership centralized
215
+
216
+ ## Pattern 4: add a list-level query variant through the facade
217
+
218
+ Use this when the resource needs a second list-style endpoint beyond the default `select(query)`.
219
+
220
+ Representative shape:
221
+
222
+ ```typescript
223
+ selectArchived(query?: ITableQuery) {
224
+ return this.$$modelResource.selectGeneral('archived', query);
225
+ }
226
+ ```
227
+
228
+ Why this is a good pattern:
229
+
230
+ - it reuses `selectGeneral(...)`
231
+ - it stays under the existing resource-owner list-key structure
232
+ - it keeps list-level semantics inside the same resource boundary
233
+
234
+ ## Pattern 5: add a custom mutation through the facade
235
+
236
+ Use this when the resource needs business actions beyond create/update/delete.
237
+
238
+ Representative shape:
239
+
240
+ ```typescript
241
+ deleteForce(id: TableIdentity) {
242
+ return this.$$modelResource.mutationItem<void, void>({
243
+ id,
244
+ action: 'deleteForce',
245
+ mutationFn: async () => {
246
+ await this.scope.api.trainingStudent.deleteForce({ params: { id } });
247
+ },
248
+ });
249
+ }
250
+ ```
251
+
252
+ Why this is a good pattern:
253
+
254
+ - it reuses `mutationItem(...)`
255
+ - it inherits centralized invalidation behavior
256
+ - it keeps mutation ownership under the same resource owner
257
+
258
+ ## Where custom business logic should live
259
+
260
+ A practical placement rule is:
261
+
262
+ ### Put it in the thin business facade when
263
+
264
+ - it is resource semantics
265
+ - it affects query or mutation ownership through the existing resource-owner
266
+ - it affects resource-level invalidation expectations
267
+ - multiple pages or blocks should reuse it
268
+ - it gives the UI a clearer business-facing surface
269
+
270
+ ### Keep it out of the business facade when
271
+
272
+ - it is only local page presentation logic
273
+ - it is one-off UI formatting with no resource ownership meaning
274
+ - it is unrelated to the resource boundary
275
+
276
+ ## A good layering pattern
277
+
278
+ A clean layering often looks like this:
279
+
280
+ - `ModelResource` → generic resource-owner runtime
281
+ - `ModelStudent` / `ModelArticle` / `ModelOrder` → thin business facade over the existing owner
282
+ - page/component controllers → consume the model and focus on page flow
283
+
284
+ That layering keeps the model architecture expressive without turning every page into a mini resource framework.
285
+
286
+ ## Common mistakes to avoid
287
+
288
+ For the broader review-oriented version of these mistakes, see [Resource Model Best Practices and Anti-Patterns](/frontend/model-resource-best-practices).
289
+
290
+ The usage mistakes to remember here are:
291
+
292
+ ### Mistake 1: creating a competing cache owner
293
+
294
+ If the business model starts owning the same list/item resource state independently, the architecture loses its single resource-owner boundary.
295
+
296
+ ### Mistake 2: bypassing the model with ad hoc `$fetch` in pages
297
+
298
+ If a page keeps calling the same resource endpoints directly while a resource-owner model already exists, the ownership boundary becomes inconsistent.
299
+
300
+ ### Mistake 3: adding wrapper classes with no semantic value
301
+
302
+ If a business model does not add real business-facing semantics, the wrapper may create extra maintenance without improving clarity.
303
+
304
+ ## A practical evolution path
305
+
306
+ A healthy evolution path often looks like this:
307
+
308
+ 1. start with direct `ModelResource` usage
309
+ 2. let generic pages/forms consume it directly
310
+ 3. add a thin business facade only when real business semantics appear
311
+ 4. keep generic page and form blocks consuming the stable resource-owner surface
312
+ 5. keep frontend follow-up thin during forward-chain contract evolution
313
+
314
+ This path keeps the abstraction proportional to the real problem and reduces mental overhead.
315
+
316
+ ## Source-reading checklist for application
317
+
318
+ When deciding how to apply `ModelResource`, ask:
319
+
320
+ 1. is the generic resource-owner already enough?
321
+ 2. does the UI need semantic business-facing methods?
322
+ 3. can the new behavior delegate to `queryItem`, `selectGeneral`, or `mutationItem`?
323
+ 4. which invalidation rules should remain centralized?
324
+ 5. which generic consumers should continue to work unchanged?
325
+
326
+ If you can answer those clearly, your application of the pattern is usually on the right track.
327
+
328
+ ## Final takeaway
329
+
330
+ The most important practical insight is simple:
331
+
332
+ > use `ModelResource` directly when the generic owner already fits; add a thin facade only when the UI needs clearer business semantics.
333
+
334
+ That approach keeps the programming model more uniform and reduces mental burden.