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,379 @@
1
+ # Resource Model Best Practices and Anti-Patterns
2
+
3
+ This guide explains practical best practices and common anti-patterns for resource-oriented models in Zova.
4
+
5
+ It assumes you have already read:
6
+
7
+ - [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)
8
+ - [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide)
9
+
10
+ Use this page when you want review guidance, design guardrails, or a practical checklist before adding or refactoring a resource model.
11
+
12
+ If you want implementation-oriented templates after the review guidance, continue with [Resource Model Cookbook](/frontend/model-resource-cookbook).
13
+
14
+ ## Why this page exists
15
+
16
+ Once a team starts using `ModelResource` and thin business facades, the next risk is not lack of capability.
17
+
18
+ The next risk is inconsistency.
19
+
20
+ Typical problems are:
21
+
22
+ - pages bypass the model and call resource endpoints directly
23
+ - invalidation rules drift across screens
24
+ - models start collecting page-only presentation details
25
+ - wrappers duplicate generic CRUD behavior without adding resource semantics
26
+ - selector identity is used inconsistently
27
+
28
+ This page exists to keep the resource-owner pattern healthy as a codebase grows.
29
+
30
+ ## The core review question
31
+
32
+ When you review a resource model, the first question should be:
33
+
34
+ > does this model own resource semantics, or is it just collecting unrelated convenience logic?
35
+
36
+ That one question catches many design mistakes early.
37
+
38
+ ## Best Practice 1: keep one stable resource-owner boundary
39
+
40
+ A good resource model should become the stable boundary for one backend resource.
41
+
42
+ That means related concerns should converge there:
43
+
44
+ - resource bootstrap
45
+ - resource API resolution
46
+ - schema access
47
+ - permissions access
48
+ - CRUD query state
49
+ - CRUD mutation state
50
+ - invalidation rules
51
+ - form-related resource semantics
52
+
53
+ ### Why this is good
54
+
55
+ It keeps pages and reusable blocks focused on page flow instead of resource plumbing.
56
+
57
+ ### Healthy sign
58
+
59
+ Multiple screens can consume the same model surface without re-deciding how the resource works.
60
+
61
+ ### Smell
62
+
63
+ Several pages each rebuild their own fetch, schema, permission, or invalidation logic for the same resource.
64
+
65
+ ## Best Practice 2: keep selector semantics explicit and consistent
66
+
67
+ If a resource model is designed to serve many concrete resource instances, selector identity should stay explicit.
68
+
69
+ ### Good pattern
70
+
71
+ - the model remains selector-aware
72
+ - cache identity stays resource-scoped
73
+ - generic consumers request the model through selector-based lookup
74
+
75
+ ### Why this matters
76
+
77
+ Selector identity is not only an IoC detail.
78
+
79
+ It is part of the runtime resource-isolation model.
80
+
81
+ ### Smell
82
+
83
+ - a resource-scoped model is reused without clear selector identity
84
+ - resource instances can accidentally share cache state
85
+ - developers stop knowing whether the model instance is generic or resource-specific
86
+
87
+ ## Best Practice 3: centralize invalidation policy in the model
88
+
89
+ A resource model should usually own the invalidation policy for its own queries and mutations.
90
+
91
+ ### Good pattern
92
+
93
+ - create, update, delete, and custom actions define invalidation behavior in the model
94
+ - list-level and item-level cache structure stay coherent
95
+ - pages trigger mutations but do not reinvent consistency rules
96
+
97
+ ### Why this matters
98
+
99
+ Invalidation policy is part of resource semantics.
100
+
101
+ If it drifts into pages, the same resource starts behaving differently across screens.
102
+
103
+ ### Smell
104
+
105
+ - one page invalidates list queries
106
+ - another page invalidates item queries
107
+ - another page manually refetches everything
108
+ - no single place explains the resource consistency model
109
+
110
+ ## Best Practice 4: put resource semantics in the model, not page trivia
111
+
112
+ A strong resource model owns semantics that belong to the resource boundary.
113
+
114
+ Examples:
115
+
116
+ - business actions such as archive/publish/approve
117
+ - schema-driven decisions
118
+ - permission-driven decisions
119
+ - resource-level computed helpers
120
+ - form submission selection rules
121
+
122
+ ### Keep out of the model
123
+
124
+ - one-off page text formatting
125
+ - view-only CSS decisions
126
+ - local widget toggles with no resource meaning
127
+ - temporary presentation hacks
128
+
129
+ ### Review question
130
+
131
+ If another page reused this resource, would this logic still belong to the same resource owner?
132
+
133
+ If the answer is no, it probably does not belong in the model.
134
+
135
+ ## Best Practice 5: add semantics only when they are real
136
+
137
+ When direct `ModelResource` usage is already enough, keep it direct.
138
+
139
+ When business semantics do appear, add them through a thin facade instead of re-expressing the same generic CRUD behavior.
140
+
141
+ ### Good pattern
142
+
143
+ - keep standard CRUD on the existing resource-owner
144
+ - add custom query methods through the thin facade
145
+ - add custom mutation methods through the thin facade
146
+ - add domain-specific computed helpers only when they improve the business-facing surface
147
+
148
+ ### Smell
149
+
150
+ A wrapper adds little more than renamed access to the same generic behavior and no new semantic rule.
151
+
152
+ That usually adds maintenance without adding clarity.
153
+
154
+ ## Best Practice 6: preserve generic consumer compatibility when valuable
155
+
156
+ A resource-facing model setup becomes more valuable when generic consumers can still work with it.
157
+
158
+ Examples of stable surfaces include:
159
+
160
+ - `select(...)`
161
+ - `view(...)`
162
+ - `permissions`
163
+ - `schemaFilter`
164
+ - `schemaRow`
165
+ - `getFormSchema(...)`
166
+ - `getFormMutationSubmit(...)`
167
+ - `getFormData(...)`
168
+
169
+ ### Why this matters
170
+
171
+ If generic page or form blocks can keep working, the codebase gains resource-specific power without losing reuse.
172
+
173
+ ### Smell
174
+
175
+ A wrapper or customization breaks existing generic consumers even though no real business need required that break.
176
+
177
+ ## Best Practice 7: keep `$fetch`, `$sdk`, and model state aligned behind one surface
178
+
179
+ A resource model is often strongest when it composes multiple frontend data layers behind one resource-facing API.
180
+
181
+ ### Good pattern
182
+
183
+ - `$fetch` handles direct transport execution
184
+ - `$sdk` handles bootstrap/schema/permission/default-value helpers
185
+ - model helpers handle query and mutation state
186
+ - pages consume one coherent model surface
187
+
188
+ ### Smell
189
+
190
+ - schema logic lives in one place
191
+ - permissions logic in another
192
+ - fetch logic in page controllers
193
+ - mutation invalidation in dialogs
194
+ - no single resource boundary remains visible
195
+
196
+ ## Best Practice 8: keep key structure intentional and readable
197
+
198
+ A good resource model should have a clear internal cache-key structure.
199
+
200
+ ### Good pattern
201
+
202
+ Use distinct identity layers such as:
203
+
204
+ - list/query scope
205
+ - row root scope
206
+ - row action scope
207
+
208
+ ### Why this matters
209
+
210
+ Readable key structure makes invalidation and debugging much easier.
211
+
212
+ ### Smell
213
+
214
+ - random string keys with no visible structure
215
+ - keys that do not reflect resource semantics
216
+ - mutation and query ownership impossible to trace mentally
217
+
218
+ ## Best Practice 9: keep bootstrap and readiness logic close to the model
219
+
220
+ If a resource needs bootstrap before normal use, keep that responsibility inside the model boundary.
221
+
222
+ ### Good pattern
223
+
224
+ - the model prepares itself before pages rely on it
225
+ - resource metadata and API resolution are model responsibilities
226
+
227
+ ### Smell
228
+
229
+ - every page must remember to prepare bootstrap manually
230
+ - some pages load metadata first while others assume it already exists
231
+ - resource readiness becomes implicit and error-prone
232
+
233
+ ## Best Practice 10: prefer incremental abstraction growth
234
+
235
+ Do not jump to the largest possible resource model on day one.
236
+
237
+ A healthy path is often:
238
+
239
+ 1. start with direct `ModelResource` usage
240
+ 2. let generic pages and forms consume the existing resource-owner surface
241
+ 3. add a thin facade only when real business semantics appear
242
+ 4. promote repeated resource logic into that stable model surface
243
+ 5. keep page logic thin where possible
244
+
245
+ ### Why this matters
246
+
247
+ Over-abstraction and under-abstraction are both expensive.
248
+
249
+ Incremental growth keeps the model proportional to the real business shape.
250
+
251
+ ## Anti-Pattern 1: page-driven resource ownership
252
+
253
+ ### What it looks like
254
+
255
+ Pages call resource endpoints directly, choose their own invalidation, and only use the model selectively.
256
+
257
+ ### Why it is harmful
258
+
259
+ The codebase stops having one authoritative resource boundary.
260
+
261
+ ### Better direction
262
+
263
+ Move repeated resource semantics back into the model and let pages focus on page flow.
264
+
265
+ ## Anti-Pattern 2: model as a dumping ground
266
+
267
+ ### What it looks like
268
+
269
+ The resource model accumulates unrelated helpers only because “it was convenient”.
270
+
271
+ ### Why it is harmful
272
+
273
+ The model loses semantic clarity and becomes hard to evolve.
274
+
275
+ ### Better direction
276
+
277
+ Keep the model centered on resource ownership. Move page-only or unrelated logic elsewhere.
278
+
279
+ ## Anti-Pattern 3: invalidation by folklore
280
+
281
+ ### What it looks like
282
+
283
+ Developers remember from habit which queries to invalidate, but the rules are not encoded centrally.
284
+
285
+ ### Why it is harmful
286
+
287
+ Correctness becomes person-dependent.
288
+
289
+ ### Better direction
290
+
291
+ Encode invalidation behavior inside resource mutations and keep the policy visible in one place.
292
+
293
+ ## Anti-Pattern 4: selector ambiguity
294
+
295
+ ### What it looks like
296
+
297
+ The same model is treated as generic in some places and concrete in others, without clear selector rules.
298
+
299
+ ### Why it is harmful
300
+
301
+ Cache isolation and mental ownership both become fragile.
302
+
303
+ ### Better direction
304
+
305
+ Decide whether the model is selector-scoped and keep that choice explicit in lookup and design.
306
+
307
+ ## Anti-Pattern 5: add a wrapper for branding only
308
+
309
+ ### What it looks like
310
+
311
+ A team creates `ModelStudent`, `ModelCourse`, `ModelOrder`, and each one only re-labels the existing resource-owner without adding meaning.
312
+
313
+ ### Why it is harmful
314
+
315
+ The codebase grows more types but not more clarity.
316
+
317
+ ### Better direction
318
+
319
+ Add a thin facade only when it contributes real business-facing semantics, reusable helpers, or clearer forward-chain frontend follow-up.
320
+
321
+ ## Anti-Pattern 6: breaking generic blocks without benefit
322
+
323
+ ### What it looks like
324
+
325
+ A wrapper or customization removes or reshapes stable resource-owner surfaces that generic blocks depend on, even though no real business need requires it.
326
+
327
+ ### Why it is harmful
328
+
329
+ You lose reuse and create unnecessary divergence.
330
+
331
+ ### Better direction
332
+
333
+ Preserve stable surfaces when possible and add custom semantics around them.
334
+
335
+ ## Anti-Pattern 7: hiding important resource semantics in pages
336
+
337
+ ### What it looks like
338
+
339
+ Pages decide custom actions, form submission logic, or permission-based branching that really belong to the resource itself.
340
+
341
+ ### Why it is harmful
342
+
343
+ The same resource starts behaving differently depending on which page happens to own the branch.
344
+
345
+ ### Better direction
346
+
347
+ Promote resource-level semantics into the model so all consumers inherit the same rules.
348
+
349
+ ## Review checklist
350
+
351
+ Use this checklist before merging resource-model changes:
352
+
353
+ 1. Is the resource-owner boundary still clear?
354
+ 2. Are selector semantics explicit and consistent?
355
+ 3. Are invalidation rules centralized in the model?
356
+ 4. Does the model own resource semantics rather than page trivia?
357
+ 5. Does the wrapper or facade add real value instead of CRUD duplication?
358
+ 6. Are generic consumers preserved where practical?
359
+ 7. Is the key structure readable and intentional?
360
+ 8. Does bootstrap/readiness stay inside the model boundary?
361
+ 9. Are `$fetch`, `$sdk`, and model state composed coherently?
362
+ 10. Would another screen reuse this model surface confidently?
363
+
364
+ ## When to use this page
365
+
366
+ Use this page when:
367
+
368
+ - reviewing a resource-model pull request
369
+ - deciding whether direct `ModelResource` usage is enough or a thin facade is justified
370
+ - cleaning up a resource model that feels bloated or inconsistent
371
+ - checking whether page logic has started to steal resource ownership
372
+
373
+ ## Final takeaway
374
+
375
+ The most important discipline is simple:
376
+
377
+ > a good resource model is neither a thin CRUD forwarding shell nor a dumping ground. It is a stable owner of resource semantics.
378
+
379
+ That is the standard to optimize for when using the resource-owner pattern in Zova.