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,238 @@
1
+ # ModelResource Internals Deep Dive
2
+
3
+ This guide explains the internals of `ModelResource` in Zova through the current public Cabloy Basic source.
4
+
5
+ Use this page when you want to understand:
6
+
7
+ - how `ModelResource` bootstraps itself
8
+ - how `resourceApi` is resolved
9
+ - where permissions, schemas, and form-provider surfaces come from
10
+ - how query, mutation, and form helpers are organized
11
+ - how query-key prefixing and invalidation work
12
+ - why `ModelResource` is the stable resource-owner boundary under both list and entry pages
13
+
14
+ ## Why this page exists
15
+
16
+ This page is the third layer of a small source-reading chain around same-resource model facades:
17
+
18
+ 1. [Model Architecture](/frontend/model-architecture) for the broader role of Zova Model
19
+ 2. [Generated Contract Consumption: Entry Branch](/frontend/generated-contract-consumption-entry-branch) for the consumer-side handoff into the owner
20
+ 3. this page for the owner internals that make that handoff work
21
+
22
+ Several existing docs already explain the meaning and usage of the resource owner well:
23
+
24
+ - [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern) explains the architecture and why the owner boundary exists
25
+ - [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide) explains application-level usage patterns
26
+ - [Resource Model Best Practices](/frontend/model-resource-best-practices) and [Resource Model Cookbook](/frontend/model-resource-cookbook) explain review and implementation guidance
27
+ - [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood) explains the module/runtime bridge around the owner
28
+
29
+ What those pages do not isolate directly is the one source-first path through `ModelResource` itself.
30
+
31
+ That is the gap this page fills.
32
+
33
+ ## The shortest accurate mental model
34
+
35
+ A practical mental model is:
36
+
37
+ 1. `ModelResource` is a selector-backed owner keyed by `resource`
38
+ 2. bootstrap resolves the final `resourceApi`
39
+ 3. the owner exposes computed surfaces for permissions, schema, and form provider
40
+ 4. query helpers wrap the shared model/query runtime for select/view/item-style fetches
41
+ 5. mutation helpers wrap the shared model/query runtime for create/update/delete behavior
42
+ 6. form helpers let pages choose schema/data/mutation behavior from `formMeta`
43
+ 7. query keys and invalidation are centralized as part of the owner contract
44
+
45
+ That means `ModelResource` is not only a fetch helper. It is the stable resource semantics boundary for the frontend.
46
+
47
+ ## Source-confirmed reading path
48
+
49
+ When reading this topic, use this order:
50
+
51
+ 1. `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts`
52
+ 2. `zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts`
53
+ 3. `zova/packages-zova/zova-core/src/core/sys/util.ts`
54
+ 4. `zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useQuery.ts`
55
+ 5. `zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.query.ts`
56
+ 6. `zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.persister.ts`
57
+ 7. `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsx`
58
+ 8. `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/entry/controller.tsx`
59
+
60
+ That order moves from the owner core, to the OpenAPI model it relies on, to path/config helpers, to query/persister behavior, and finally to the clearest current consumers.
61
+
62
+ ## Initialization and bootstrap
63
+
64
+ The owner core lives in:
65
+
66
+ ```text
67
+ zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts
68
+ ```
69
+
70
+ The first source-confirmed facts are:
71
+
72
+ - `@Model({ enableSelector: true })`
73
+ - `__init__(resource)` requires a concrete `resource`
74
+ - bootstrap happens before downstream consumers use the owner surfaces
75
+
76
+ This matters because `ModelResource` is not one global singleton.
77
+
78
+ It is a selector-backed owner whose runtime identity is the current resource name.
79
+
80
+ ## `resourceApi` resolution
81
+
82
+ The bootstrap path uses:
83
+
84
+ - `this.$sdk.getBootstrap(this.resource)`
85
+ - `this.sys.util.parseResourceApi(resource, api)`
86
+
87
+ The path/config helper lives in:
88
+
89
+ ```text
90
+ zova/packages-zova/zova-core/src/core/sys/util.ts
91
+ ```
92
+
93
+ This confirms the owner flow:
94
+
95
+ - bootstrap data may override the final API path
96
+ - otherwise the resource name is translated into a default controller/action API path
97
+
98
+ That is why `resourceApi` should be treated as an owner-level resolved surface, not as one hard-coded string duplicated across pages.
99
+
100
+ ## Metadata surfaces exposed by the owner
101
+
102
+ Inside `ModelResource`, the owner computes and exposes:
103
+
104
+ - `permissions`
105
+ - `formProvider`
106
+ - `schemaView`
107
+ - `schemaCreate`
108
+ - `schemaUpdate`
109
+ - `schemaFilter`
110
+ - `schemaRow`
111
+ - `schemaPages`
112
+
113
+ These surfaces are derived from:
114
+
115
+ - the bootstrap/runtime resource context
116
+ - the OpenAPI SDK/schema helpers
117
+
118
+ This is the clearest source-confirmed reason why both list pages and entry pages reuse the same owner: schema, permission, and provider surfaces belong to one resource boundary.
119
+
120
+ ## Query helper layer
121
+
122
+ The query helpers are organized around:
123
+
124
+ - `selectGeneral(actionPath?, query?)`
125
+ - `select(query?)`
126
+ - `queryItem(...)`
127
+ - `view(id)`
128
+
129
+ `select(query?)` is only a thin wrapper over `selectGeneral(undefined, query)`.
130
+
131
+ The important source-confirmed detail is that the select key includes a hash of the query object:
132
+
133
+ - `['select', actionPath ?? '', hashkey(query)]`
134
+
135
+ That means query identity is deliberate and owner-controlled.
136
+
137
+ This is the owner-side boundary for list/query fetches, not the page shell.
138
+
139
+ ## Mutation helper layer
140
+
141
+ The mutation helpers are organized around:
142
+
143
+ - `create()`
144
+ - `mutationItem(...)`
145
+ - `update(id)`
146
+ - `delete(id)`
147
+
148
+ The most important source-confirmed behavior is:
149
+
150
+ - select queries are invalidated after successful mutations
151
+ - item-root queries are invalidated for the specific row identity
152
+
153
+ That means mutation helpers do not only perform network requests. They also own the default resource-level invalidation policy.
154
+
155
+ ## Form helper layer
156
+
157
+ The form-facing helpers are:
158
+
159
+ - `getFormSchema(formMeta)`
160
+ - `getFormApiSchemas(formMeta)`
161
+ - `getFormMutationSubmit(formMeta, id?)`
162
+ - `getFormData(formMeta, id?)`
163
+ - `getQueryDataDefaultValue(schemaName?)`
164
+
165
+ This is the clearest source-confirmed bridge from resource owner to entry-page form runtime.
166
+
167
+ A practical reading rule is:
168
+
169
+ - list pages mainly consume `schemaFilter`, `schemaRow`, and `select(...)`
170
+ - entry pages mainly consume `formMeta`-driven form helpers
171
+
172
+ ## Query-key prefixing and invalidation behavior
173
+
174
+ The shared model/query behavior lives in:
175
+
176
+ ```text
177
+ zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useQuery.ts
178
+ zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.query.ts
179
+ zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.persister.ts
180
+ ```
181
+
182
+ The important source-confirmed behavior is:
183
+
184
+ - owner query keys are prefixed with bean full name
185
+ - selector-backed models also prefix by selector
186
+ - persister/query behavior therefore treats one resource owner as a distinct query namespace
187
+
188
+ This is why `ModelResource` query identity is stable even when multiple resources or multiple selectors exist at once.
189
+
190
+ ## Current consumers that prove the contract
191
+
192
+ The clearest current consumers are:
193
+
194
+ - `rest-resource/src/page/resource/controller.tsx`
195
+ - `rest-resource/src/page/entry/controller.tsx`
196
+
197
+ These page shells prove that:
198
+
199
+ - list pages consume the owner for top-level list/schema/runtime entry
200
+ - entry pages consume the owner for form/provider/schema/runtime entry
201
+
202
+ That is enough to verify that `ModelResource` is the shared owner beneath both branches.
203
+
204
+ ## What this guide does not re-explain
205
+
206
+ This page does **not** fully re-explain:
207
+
208
+ - why the resource owner pattern exists -> see [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)
209
+ - application-level facade and usage guidance -> see [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide)
210
+ - the full list-page runtime -> see [Resource List Page Deep Dive](/frontend/resource-list-page-deep-dive)
211
+ - the full entry-page runtime -> see [Resource Entry Page Deep Dive](/frontend/resource-entry-page-deep-dive)
212
+
213
+ Its job is only to explain the owner internals and their current consumer contract.
214
+
215
+ ## Where to read next
216
+
217
+ Use these next steps depending on your question:
218
+
219
+ - if you want to step back to the broader model role, return to [Model Architecture](/frontend/model-architecture)
220
+ - if you want to step back to the consumer-side handoff, return to [Generated Contract Consumption: Entry Branch](/frontend/generated-contract-consumption-entry-branch)
221
+ - if you want the list-page runtime branch, read [Resource List Page Deep Dive](/frontend/resource-list-page-deep-dive)
222
+ - if you want the entry-page runtime branch, read [Resource Entry Page Deep Dive](/frontend/resource-entry-page-deep-dive)
223
+ - if you want the owner-pattern explanation, read [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)
224
+ - if you want application-level usage/facade rules, read [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide)
225
+
226
+ ## Final takeaway
227
+
228
+ The most accurate way to read `ModelResource` is not as one generic CRUD helper.
229
+
230
+ Read it as the selector-backed resource owner that:
231
+
232
+ - bootstraps and resolves `resourceApi`
233
+ - exposes schema, permission, and provider surfaces
234
+ - owns query, mutation, and form helper boundaries
235
+ - defines query-key and invalidation behavior
236
+ - remains the stable resource semantics layer beneath both list pages and entry pages
237
+
238
+ That is the source-confirmed role of `ModelResource` in the current Cabloy Basic frontend architecture.
@@ -0,0 +1,402 @@
1
+ # Model Resource Owner Pattern
2
+
3
+ This guide explains the resource-owner pattern built on top of Zova Model.
4
+
5
+ It uses the current `rest-resource` model as the main source specimen:
6
+
7
+ - `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts`
8
+
9
+ Read [Model Architecture](/frontend/model-architecture) and [Model State Guide](/frontend/model-state-guide) first if you want the broader Model runtime and helper surface.
10
+
11
+ If your next question is how `ModelResource` itself works internally at the source level, continue with [ModelResource Internals Deep Dive](/frontend/model-resource-internals-deep-dive).
12
+
13
+ If your next question is how the generic lower-level model runtime works beneath `ModelResource`, continue with [Model Runtime Under the Hood](/frontend/a-model-under-the-hood).
14
+
15
+ If your next question is how the whole `rest-resource` module works at runtime beyond the model itself, continue with [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood).
16
+
17
+ If your next question is which files to read next for that runtime, continue with [Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map).
18
+
19
+ If your next question is how to apply this pattern in your own module, continue with [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide).
20
+
21
+ If your next question is how to review or constrain that pattern in a larger codebase, continue with [Resource Model Best Practices and Anti-Patterns](/frontend/model-resource-best-practices).
22
+
23
+ If your next question is which common extension shapes to implement first, continue with [Resource Model Cookbook](/frontend/model-resource-cookbook).
24
+
25
+ > [!TIP]
26
+ > **Resource docs path**
27
+ >
28
+ > 1. **[Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)** — learn why `ModelResource` is a resource owner
29
+ > 2. **[Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood)** — learn how the module runtime pieces cooperate
30
+ > 3. **[Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map)** — learn which files to read next
31
+ > 4. **[Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide)** — learn how to reuse the owner in application code
32
+ > 5. **[Resource Model Best Practices](/frontend/model-resource-best-practices)** — learn the review guardrails
33
+ > 6. **[Resource Model Cookbook](/frontend/model-resource-cookbook)** — learn the common implementation shapes
34
+ >
35
+ > **You are here:** step 1.
36
+ > **Next recommended page:** [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood).
37
+
38
+ ## Why this page exists
39
+
40
+ Many examples of Zova Model start from a small feature model:
41
+
42
+ - one list query
43
+ - one item query
44
+ - one or two mutations
45
+
46
+ Those examples are useful, but they can accidentally make Model look smaller than it really is.
47
+
48
+ The `rest-resource` specimen shows a larger pattern:
49
+
50
+ > a model can become the stable owner of one whole resource domain boundary.
51
+
52
+ That means the model is no longer only a query wrapper.
53
+
54
+ It becomes the place that owns:
55
+
56
+ - resource bootstrap
57
+ - schema access
58
+ - permissions access
59
+ - form integration
60
+ - query state
61
+ - mutation state
62
+ - cache invalidation policy
63
+
64
+ This page explains that pattern explicitly.
65
+
66
+ ## What “resource owner” means in Zova
67
+
68
+ In this context, a resource-owner model is a model bean that becomes the reusable frontend boundary for one backend resource.
69
+
70
+ It is responsible for presenting one coherent surface to the rest of the UI.
71
+
72
+ Instead of asking every page, table, form, and action to individually know:
73
+
74
+ - how to resolve the resource API path
75
+ - how to fetch list data
76
+ - how to fetch row data
77
+ - how to submit create/update/delete requests
78
+ - how to obtain schema metadata
79
+ - how to choose invalidation rules
80
+
81
+ those decisions are centralized inside the model.
82
+
83
+ A practical reading takeaway is:
84
+
85
+ > the resource-owner model is the frontend resource facade.
86
+
87
+ ## The source specimen
88
+
89
+ The main example is:
90
+
91
+ - `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts`
92
+
93
+ This class is generic:
94
+
95
+ ```typescript
96
+ export class ModelResource<
97
+ Entity = any,
98
+ EntityCreate = Partial<Entity>,
99
+ EntityUpdate = Partial<Entity>,
100
+ > extends BeanModelBase {}
101
+ ```
102
+
103
+ That already tells you something important.
104
+
105
+ This model is designed to be reused across many resource types rather than tied to one page.
106
+
107
+ ## Why `enableSelector` is essential
108
+
109
+ The class is decorated like this:
110
+
111
+ ```typescript
112
+ @Model<IModelOptionsResource>({
113
+ enableSelector: true,
114
+ })
115
+ ```
116
+
117
+ This matters because one generic `ModelResource` class needs to serve many different resources.
118
+
119
+ The resource name is passed into initialization:
120
+
121
+ ```typescript
122
+ protected async __init__(resource: string) {
123
+ await super.__init__(resource);
124
+ this.resource = resource;
125
+ ...
126
+ }
127
+ ```
128
+
129
+ That means the selector becomes the runtime identity for the concrete resource instance.
130
+
131
+ So even when many consumers reuse the same generic class, each resource instance stays isolated.
132
+
133
+ This is not only conceptual isolation.
134
+
135
+ It also affects cache identity.
136
+
137
+ Because Zova Model prefixes query keys by bean identity and selector, the effective cache keys are separated by resource.
138
+
139
+ So logical keys such as:
140
+
141
+ ```typescript
142
+ ['select', '', hashkey(query)][('item', id, 'view')];
143
+ ```
144
+
145
+ can safely exist for many resources without colliding.
146
+
147
+ ## Bootstrap before normal state usage
148
+
149
+ A small feature model often starts using queries immediately.
150
+
151
+ `ModelResource` adds a bootstrap step first:
152
+
153
+ ```typescript
154
+ protected async __init__(resource: string) {
155
+ ...
156
+ await this._bootstrap();
157
+ }
158
+ ```
159
+
160
+ And `_bootstrap()` uses:
161
+
162
+ ```typescript
163
+ const queryBootstrap = await $QueryAutoLoad(() => this.$sdk.getBootstrap(this.resource));
164
+ ```
165
+
166
+ Then it resolves:
167
+
168
+ ```typescript
169
+ this.resourceApi = this.sys.util.parseResourceApi(this.resource, queryBootstrap.data.apiPath);
170
+ ```
171
+
172
+ This is an important pattern.
173
+
174
+ The model does not assume that the final operational API path is already known as a hardcoded constant.
175
+
176
+ Instead, it loads resource metadata first, then turns that metadata into the stable runtime resource API boundary.
177
+
178
+ That is one reason this model is better understood as infrastructure rather than only CRUD sugar.
179
+
180
+ ## The model owns resource metadata surfaces
181
+
182
+ Inside `__init__`, the model exposes several computed resource-level surfaces:
183
+
184
+ - `permissions`
185
+ - `formProvider`
186
+ - `schemaView`
187
+ - `schemaCreate`
188
+ - `schemaUpdate`
189
+ - `schemaFilter`
190
+ - `schemaRow`
191
+ - `schemaPages`
192
+
193
+ These are not random conveniences.
194
+
195
+ They show that the model owns not only request state, but also the metadata that resource UIs need in order to render and behave correctly.
196
+
197
+ For example:
198
+
199
+ - permissions affect whether UI actions are available
200
+ - schemas affect view/create/edit/filter rendering
201
+ - form provider affects how forms are assembled
202
+
203
+ This is exactly the kind of cross-cutting ownership that fits a resource-owner model.
204
+
205
+ ## Query ownership pattern
206
+
207
+ The query side is organized around a reusable internal structure.
208
+
209
+ ### List/query state
210
+
211
+ The model exposes list-style querying through:
212
+
213
+ - `selectGeneral(actionPath?, query?)`
214
+ - `select(query?)`
215
+
216
+ These methods use `$useStateData(...)` and place query ownership inside the model.
217
+
218
+ That means the page does not own the fetch details or cache-key policy.
219
+
220
+ ### Row-specific query state
221
+
222
+ The model exposes item-style querying through:
223
+
224
+ - `queryItem(...)`
225
+ - `view(id)`
226
+
227
+ Again, the page consumes a stable model API rather than building row fetch rules ad hoc.
228
+
229
+ A practical reading takeaway is:
230
+
231
+ > pages consume resource semantics; the model owns query semantics.
232
+
233
+ ## Mutation ownership pattern
234
+
235
+ The mutation side follows the same idea.
236
+
237
+ The model does not expose only one-off raw mutation calls.
238
+
239
+ Instead, it builds a reusable mutation layer:
240
+
241
+ - `create()`
242
+ - `update(id)`
243
+ - `delete(id)`
244
+ - `mutationItem(...)`
245
+
246
+ This gives the model one place to enforce mutation-key conventions and invalidation rules.
247
+
248
+ That is an important architectural advantage.
249
+
250
+ Without this model boundary, every page or dialog could invent slightly different invalidation behavior.
251
+
252
+ ## Cache-key design
253
+
254
+ One of the best design lessons in this specimen is the cache-key structure.
255
+
256
+ The class defines three related key helpers:
257
+
258
+ ```typescript
259
+ protected keySelect(actionPath?: string, query?: ITableQuery) {
260
+ return ['select', actionPath ?? '', hashkey(query)] as const;
261
+ }
262
+
263
+ protected keyItemRoot(id: TableIdentity) {
264
+ return ['item', id] as const;
265
+ }
266
+
267
+ protected keyItem(id: TableIdentity, action: string) {
268
+ return ['item', id, action] as const;
269
+ }
270
+ ```
271
+
272
+ This separates resource state into three layers:
273
+
274
+ - list/query scope
275
+ - row root scope
276
+ - row action scope
277
+
278
+ That structure gives the model precise invalidation control.
279
+
280
+ ## Invalidation policy as model-owned policy
281
+
282
+ The model also centralizes invalidation behavior.
283
+
284
+ ### Create
285
+
286
+ `create()` invalidates:
287
+
288
+ - `['select']`
289
+
290
+ That makes sense because a new row affects list-level state first.
291
+
292
+ ### Update/Delete
293
+
294
+ `mutationItem(...)` invalidates:
295
+
296
+ - `['select']`
297
+ - `keyItemRoot(id)`
298
+
299
+ That means:
300
+
301
+ - list views refresh when row mutations change aggregate list state
302
+ - row-specific state refreshes when one row changes
303
+
304
+ This is a very important design point.
305
+
306
+ The model itself defines consistency rules for resource state.
307
+
308
+ That keeps cache policy close to resource semantics rather than scattering it across UI code.
309
+
310
+ ## Form integration pattern
311
+
312
+ `ModelResource` also owns form-facing behavior.
313
+
314
+ Representative methods:
315
+
316
+ - `getFormSchema(formMeta)`
317
+ - `getFormApiSchemas(formMeta)`
318
+ - `getFormMutationSubmit(formMeta, id?)`
319
+ - `getFormData(formMeta, id?)`
320
+ - `getQueryDataDefaultValue(schemaName?)`
321
+
322
+ This is what makes the model a real resource facade instead of only a transport helper.
323
+
324
+ The model translates resource semantics into form semantics.
325
+
326
+ For example:
327
+
328
+ - create form → use create schema and create mutation
329
+ - update form → use update schema and update mutation
330
+ - view form → use view schema and row data query
331
+
332
+ This keeps form orchestration aligned with the same resource owner that already owns queries and mutations.
333
+
334
+ ## Relationship to `$fetch`, `$sdk`, and OpenAPI
335
+
336
+ `ModelResource` also shows how multiple frontend data layers can be composed cleanly.
337
+
338
+ Inside one model boundary it uses:
339
+
340
+ - `$fetch` for direct REST request execution
341
+ - `$sdk` for bootstrap, schema, permissions, and default-value helpers
342
+ - model helpers for cached query/mutation state
343
+
344
+ That composition matters.
345
+
346
+ It shows that the server-data ladder is not a set of isolated choices.
347
+
348
+ A higher-level model can combine those layers into one coherent business-facing API.
349
+
350
+ ## When to use this pattern
351
+
352
+ Use a resource-owner model when:
353
+
354
+ - many screens or widgets depend on the same backend resource
355
+ - schema metadata, permissions, and CRUD behavior should stay aligned
356
+ - form behavior should stay aligned with the same resource owner
357
+ - cache invalidation rules should be centralized
358
+ - you want one stable frontend boundary for resource-level business semantics
359
+
360
+ This pattern is especially strong for admin-style, resource-driven UIs.
361
+
362
+ ## When not to use this pattern
363
+
364
+ Do not reach for this pattern by default when:
365
+
366
+ - the state is truly page-local and disposable
367
+ - the feature only needs one tiny query with no reusable semantics
368
+ - there is no meaningful resource-level schema/permission/form ownership
369
+ - adding a generic resource facade would be heavier than the real business problem
370
+
371
+ In those cases, a smaller feature model may be the better fit.
372
+
373
+ ## A useful comparison
374
+
375
+ A compact comparison is:
376
+
377
+ - `demo-todo` → minimal feature model pattern
378
+ - `home-passport` → SSR-sensitive state ownership pattern
379
+ - `rest-resource` → generic reusable resource-owner pattern
380
+
381
+ Use these three together when reading how far Zova Model can scale.
382
+
383
+ ## Source-reading checklist
384
+
385
+ When you read `ModelResource`, focus on these questions:
386
+
387
+ 1. where does the selector identity come from?
388
+ 2. where does `resourceApi` become available?
389
+ 3. which state belongs to list scope vs row scope?
390
+ 4. which invalidation rules belong to each mutation?
391
+ 5. which responsibilities are query-related and which are schema/form-related?
392
+ 6. what would become duplicated across pages if this model did not exist?
393
+
394
+ Those questions will help you see the architectural pattern, not only the method list.
395
+
396
+ ## Final takeaway
397
+
398
+ The most important insight is simple:
399
+
400
+ > a Zova model can be more than a data hook wrapper. `ModelResource` can become the stable owner of one whole frontend resource boundary.
401
+
402
+ In application code, prefer using that owner directly or adding a thin facade over it, rather than creating a competing second owner for the same resource.