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.
- package/.claude/hooks/contract-loop-gate.ts +296 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/cabloy-backend-scaffold/SKILL.md +2 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -0
- package/.claude/skills/cabloy-contract-loop/SKILL.md +89 -16
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
- package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
- package/.claude/skills/cabloy-domain-planning/SKILL.md +212 -0
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -0
- package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
- package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +7 -0
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
- package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
- package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
- package/CHANGELOG.md +64 -0
- package/CLAUDE.md +11 -0
- package/cabloy-docs/.vitepress/config.mjs +197 -5
- package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +22 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +12 -7
- package/cabloy-docs/ai/introduction.md +1 -0
- package/cabloy-docs/ai/playbook-backend-module.md +6 -0
- package/cabloy-docs/ai/playbook-module-removal.md +164 -0
- package/cabloy-docs/ai/skills.md +12 -0
- package/cabloy-docs/backend/backend-contract-emission-output-inspection.md +189 -0
- package/cabloy-docs/backend/backend-contract-emission-source-reading-map.md +160 -0
- package/cabloy-docs/backend/backend-contract-emission-specimen.md +170 -0
- package/cabloy-docs/backend/backend-resource-module-contract-chain.md +323 -0
- package/cabloy-docs/backend/backend-source-reading-debug-checklist.md +173 -0
- package/cabloy-docs/backend/backend-source-reading-roadmap.md +129 -0
- package/cabloy-docs/backend/backend-source-reading-verify-playbook.md +166 -0
- package/cabloy-docs/backend/bean-scene-authoring.md +4 -4
- package/cabloy-docs/backend/broadcast-guide.md +3 -3
- package/cabloy-docs/backend/cli.md +20 -11
- package/cabloy-docs/backend/config-guide.md +4 -4
- package/cabloy-docs/backend/controller-aop-guide.md +10 -10
- package/cabloy-docs/backend/controller-guide.md +12 -2
- package/cabloy-docs/backend/crud-workflow.md +7 -3
- package/cabloy-docs/backend/dto-guide.md +18 -2
- package/cabloy-docs/backend/dto-infer-generation.md +201 -25
- package/cabloy-docs/backend/election-guide.md +2 -2
- package/cabloy-docs/backend/entity-guide.md +30 -3
- package/cabloy-docs/backend/error-guide.md +3 -3
- package/cabloy-docs/backend/event-guide.md +4 -4
- package/cabloy-docs/backend/external-aop-guide.md +2 -2
- package/cabloy-docs/backend/field-indexes.md +9 -3
- package/cabloy-docs/backend/foundation.md +8 -8
- package/cabloy-docs/backend/i18n-guide.md +6 -6
- package/cabloy-docs/backend/internal-aop-guide.md +2 -2
- package/cabloy-docs/backend/introduction.md +15 -0
- package/cabloy-docs/backend/migration-and-changes.md +3 -3
- package/cabloy-docs/backend/model-guide.md +16 -6
- package/cabloy-docs/backend/openapi-guide.md +3 -0
- package/cabloy-docs/backend/queue-guide.md +3 -3
- package/cabloy-docs/backend/redlock-guide.md +2 -2
- package/cabloy-docs/backend/schedule-guide.md +2 -2
- package/cabloy-docs/backend/scripts.md +8 -0
- package/cabloy-docs/backend/serialization-guide.md +12 -2
- package/cabloy-docs/backend/service-guide.md +18 -9
- package/cabloy-docs/backend/startup-guide.md +5 -5
- package/cabloy-docs/backend/status-guide.md +271 -0
- package/cabloy-docs/backend/unit-testing.md +3 -3
- package/cabloy-docs/backend/vona-source-reading-map.md +157 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +5 -5
- package/cabloy-docs/backend/websocket-usage-guide.md +15 -8
- package/cabloy-docs/frontend/a-model-under-the-hood.md +281 -0
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +248 -0
- package/cabloy-docs/frontend/a-router-guide.md +307 -0
- package/cabloy-docs/frontend/api-guide.md +6 -4
- package/cabloy-docs/frontend/api-schema-guide.md +1 -0
- package/cabloy-docs/frontend/app-startup-guide.md +7 -4
- package/cabloy-docs/frontend/bean-scene-authoring.md +3 -1
- package/cabloy-docs/frontend/behavior-guide.md +16 -16
- package/cabloy-docs/frontend/cli.md +14 -2
- package/cabloy-docs/frontend/command-scene-authoring.md +504 -0
- package/cabloy-docs/frontend/component-guide.md +5 -5
- package/cabloy-docs/frontend/component-props-guide.md +1 -1
- package/cabloy-docs/frontend/component-v-model-guide.md +2 -2
- package/cabloy-docs/frontend/design-principles.md +6 -0
- package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
- package/cabloy-docs/frontend/filter-query-select-data-flow-guide.md +260 -0
- package/cabloy-docs/frontend/form-guide.md +786 -0
- package/cabloy-docs/frontend/form-scene-to-page-meta-guide.md +303 -0
- package/cabloy-docs/frontend/foundation.md +33 -0
- package/cabloy-docs/frontend/frontend-source-reading-roadmap.md +249 -0
- package/cabloy-docs/frontend/generated-contract-consumption-debug-checklist.md +190 -0
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +205 -0
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +157 -0
- package/cabloy-docs/frontend/generated-contract-consumption-specimen.md +203 -0
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +189 -0
- package/cabloy-docs/frontend/generic-component-guide.md +1 -1
- package/cabloy-docs/frontend/introduction.md +38 -5
- package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
- package/cabloy-docs/frontend/mock-guide.md +1 -0
- package/cabloy-docs/frontend/model-architecture.md +288 -39
- package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
- package/cabloy-docs/frontend/model-resource-cookbook.md +508 -0
- package/cabloy-docs/frontend/model-resource-internals-deep-dive.md +238 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +402 -0
- package/cabloy-docs/frontend/model-resource-usage-guide.md +334 -0
- package/cabloy-docs/frontend/model-state-guide.md +371 -15
- package/cabloy-docs/frontend/module-scope.md +8 -8
- package/cabloy-docs/frontend/modules-and-suites.md +2 -1
- package/cabloy-docs/frontend/navigation-guards-guide.md +7 -0
- package/cabloy-docs/frontend/openapi-sdk-guide.md +17 -6
- package/cabloy-docs/frontend/page-guide.md +15 -9
- package/cabloy-docs/frontend/page-meta-guide.md +466 -0
- package/cabloy-docs/frontend/page-params-guide.md +3 -3
- package/cabloy-docs/frontend/page-query-guide.md +2 -2
- package/cabloy-docs/frontend/page-route-guide.md +6 -0
- package/cabloy-docs/frontend/permission-formscene-action-visibility-guide.md +263 -0
- package/cabloy-docs/frontend/quickstart.md +18 -2
- package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +271 -0
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +279 -0
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +522 -0
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +622 -0
- package/cabloy-docs/frontend/root-behaviors-guide.md +282 -0
- package/cabloy-docs/frontend/route-alias-guide.md +6 -0
- package/cabloy-docs/frontend/router-stack-guide.md +229 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +26 -3
- package/cabloy-docs/frontend/router-tabs-layout-integration.md +367 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +6 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +7 -0
- package/cabloy-docs/frontend/router-tabs-vs-stack.md +167 -0
- package/cabloy-docs/frontend/router-view-hosts-guide.md +450 -0
- package/cabloy-docs/frontend/server-data.md +4 -1
- package/cabloy-docs/frontend/system-startup-guide.md +2 -2
- package/cabloy-docs/frontend/table-action-visibility-permission-flow-guide.md +263 -0
- package/cabloy-docs/frontend/table-cell-cookbook.md +568 -0
- package/cabloy-docs/frontend/table-guide.md +373 -0
- package/cabloy-docs/frontend/table-resource-crud-cookbook.md +496 -0
- package/cabloy-docs/frontend/zova-app-guide.md +251 -0
- package/cabloy-docs/frontend/zova-form-source-reading-map.md +293 -0
- package/cabloy-docs/frontend/zova-form-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-source-reading-map.md +421 -0
- package/cabloy-docs/frontend/zova-table-controller-render-supplement.md +225 -0
- package/cabloy-docs/frontend/zova-table-source-reading-map.md +317 -0
- package/cabloy-docs/frontend/zova-table-under-the-hood.md +532 -0
- package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist.md +245 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map.md +139 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook.md +248 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions.md +511 -0
- package/cabloy-docs/fullstack/contract-loop-playbook.md +356 -0
- package/cabloy-docs/fullstack/edition-collaboration-differences.md +6 -0
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +199 -23
- package/cabloy-docs/fullstack/introduction.md +15 -1
- package/cabloy-docs/fullstack/openapi-to-sdk.md +135 -11
- package/cabloy-docs/fullstack/suites-and-modules.md +333 -0
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +3 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +4 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +6 -2
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +60 -23
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +14 -7
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +6 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +17 -4
- package/cabloy-docs/reference/bean-scene-boilerplates.md +15 -13
- package/cabloy-docs/reference/package-map.md +4 -3
- package/package.json +2 -1
- package/scripts/init.ts +2 -18
- package/scripts/initTestData.ts +25 -0
- package/scripts/upgrade.ts +17 -2
- package/vona/pnpm-lock.yaml +48 -194
- package/vona/src/suite/a-training/modules/training-student/package.json +53 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +400 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +18 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +12 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +21 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/ssrMenu.student.ts +29 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +74 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectReq.tsx +44 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectRes.tsx +11 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +45 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +42 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +25 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +84 -0
- package/vona/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +10 -0
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +57 -0
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +173 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.build.json +11 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.json +7 -0
- package/vona/src/suite/a-training/package.json +12 -0
- package/vona/src/suite/a-training/tsconfig.base.json +4 -0
- package/vona/src/suite/a-training/tsconfig.json +10 -0
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +416 -690
- package/zova/src/suite/a-training/modules/training-student/cli/openapi.config.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/package.json +52 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/component/formFieldLevel.ts +31 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +258 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +196 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +4146 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +151 -0
- package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +43 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionDeleteForce.tsx +51 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +56 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.level.tsx +63 -0
- package/zova/src/suite/a-training/modules/training-student/src/component/formFieldLevel/controller.tsx +117 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +42 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.build.json +13 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.json +5 -0
- package/zova/src/suite/a-training/package.json +12 -0
- package/zova/src/suite/a-training/tsconfig.base.json +4 -0
- package/zova/src/suite/a-training/tsconfig.json +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +29 -7
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/select/controller.tsx +34 -11
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +3 -3
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/lib/tableCell.ts +1 -1
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
|
@@ -1,28 +1,50 @@
|
|
|
1
1
|
# Model State Guide
|
|
2
2
|
|
|
3
|
-
This guide explains how model-
|
|
3
|
+
This guide explains how to author and consume model-managed state in Zova within the Cabloy monorepo.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Read [Model Architecture](/frontend/model-architecture) first if you want the broader architectural role of Model.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
If you specifically want the scalable resource-facade pattern, continue with [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
If you want the generic lower-level model runtime beneath these helper families, continue with [A-Model Under the Hood](/frontend/a-model-under-the-hood).
|
|
10
|
+
|
|
11
|
+
If you want to understand how that owner pattern expands into the whole `rest-resource` module runtime, continue with [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood), then [Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map).
|
|
12
|
+
|
|
13
|
+
If you want to apply that pattern in your own module with a more uniform two-usage model, continue with [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide).
|
|
14
|
+
|
|
15
|
+
## Why the model-state layer exists
|
|
16
|
+
|
|
17
|
+
Zova uses model-based state management so cached remote data and several local state categories can participate in one broader model system.
|
|
18
|
+
|
|
19
|
+
This improves runtime performance and developer experience by building on top of TanStack Query while keeping the developer-facing surface aligned with Zova beans.
|
|
20
|
+
|
|
21
|
+
The key point is that model state is not limited to server data.
|
|
22
|
+
|
|
23
|
+
Current `a-model` source supports a broader state family that includes:
|
|
24
|
+
|
|
25
|
+
- remote/query-style state
|
|
26
|
+
- in-memory state
|
|
27
|
+
- local-storage state
|
|
28
|
+
- cookie-backed state
|
|
29
|
+
- async persisted db state
|
|
10
30
|
|
|
11
31
|
## Create a model
|
|
12
32
|
|
|
13
|
-
Example: create a model named `menu` in module `
|
|
33
|
+
Example: create a model named `menu` in module `training-student`.
|
|
14
34
|
|
|
15
35
|
```bash
|
|
16
|
-
npm run zova :create:bean model menu -- --module=
|
|
36
|
+
npm run zova :create:bean model menu -- --module=training-student
|
|
17
37
|
```
|
|
18
38
|
|
|
19
|
-
##
|
|
39
|
+
## Basic model definition
|
|
20
40
|
|
|
21
41
|
Representative pattern:
|
|
22
42
|
|
|
23
43
|
```typescript
|
|
44
|
+
import { BeanModelBase, Model } from 'zova-module-a-model';
|
|
45
|
+
|
|
24
46
|
@Model()
|
|
25
|
-
export class ModelMenu {
|
|
47
|
+
export class ModelMenu extends BeanModelBase {
|
|
26
48
|
retrieveMenus() {
|
|
27
49
|
return this.$useStateData({
|
|
28
50
|
queryKey: ['retrieveMenus'],
|
|
@@ -36,11 +58,11 @@ export class ModelMenu {
|
|
|
36
58
|
}
|
|
37
59
|
```
|
|
38
60
|
|
|
39
|
-
This pattern
|
|
61
|
+
This pattern matters because it shows that model logic is the place where cached remote data becomes a reusable abstraction.
|
|
40
62
|
|
|
41
63
|
## Using a model
|
|
42
64
|
|
|
43
|
-
Representative pattern:
|
|
65
|
+
Representative consumption pattern:
|
|
44
66
|
|
|
45
67
|
```typescript
|
|
46
68
|
@Use()
|
|
@@ -53,18 +75,352 @@ protected render() {
|
|
|
53
75
|
}
|
|
54
76
|
```
|
|
55
77
|
|
|
78
|
+
The important point is architectural:
|
|
79
|
+
|
|
80
|
+
- the page/controller consumes the model
|
|
81
|
+
- the model owns the reusable data access and cache behavior
|
|
82
|
+
|
|
83
|
+
## The main helper families
|
|
84
|
+
|
|
85
|
+
The current source organizes model state around these helper families.
|
|
86
|
+
|
|
87
|
+
### 1. `$useStateData(...)`
|
|
88
|
+
|
|
89
|
+
Use this for cached remote data or other query-style state where the caller wants the full query object.
|
|
90
|
+
|
|
91
|
+
Representative characteristics from current source:
|
|
92
|
+
|
|
93
|
+
- it delegates to `$useQuery(...)`
|
|
94
|
+
- it memoizes the query wrapper by prefixed query key
|
|
95
|
+
- it auto-calls `suspense()` on first creation unless disabled by metadata
|
|
96
|
+
- it is the main bridge from model methods to query-style UI state
|
|
97
|
+
|
|
98
|
+
Representative example:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
findAll() {
|
|
102
|
+
return this.$useStateData({
|
|
103
|
+
queryKey: ['list'],
|
|
104
|
+
queryFn: async () => {
|
|
105
|
+
return this.scope.api.todo.findAll();
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 2. `$useMutationData(...)`
|
|
112
|
+
|
|
113
|
+
Use this for model-owned mutation state.
|
|
114
|
+
|
|
115
|
+
Current-source behavior includes:
|
|
116
|
+
|
|
117
|
+
- `mutationKey` is required
|
|
118
|
+
- the key is automatically prefixed with model identity
|
|
119
|
+
- the mutation wrapper is memoized by prefixed key
|
|
120
|
+
- default error handling is attached unless disabled
|
|
121
|
+
|
|
122
|
+
Representative example:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
create() {
|
|
126
|
+
return this.$useMutationData({
|
|
127
|
+
mutationKey: ['create'],
|
|
128
|
+
mutationFn: async body => {
|
|
129
|
+
return this.scope.api.todo.create(body);
|
|
130
|
+
},
|
|
131
|
+
onSuccess: () => {
|
|
132
|
+
this.$invalidateQueries({ queryKey: ['list'] });
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The pattern to notice is that the model owns both the mutation and the follow-up cache invalidation policy.
|
|
139
|
+
|
|
140
|
+
## 3. `$useStateMem(...)`
|
|
141
|
+
|
|
142
|
+
Use this when the state should stay only in memory.
|
|
143
|
+
|
|
144
|
+
Current-source characteristics:
|
|
145
|
+
|
|
146
|
+
- no persistence
|
|
147
|
+
- `enabled: false`
|
|
148
|
+
- `staleTime: Infinity`
|
|
149
|
+
- still uses model-owned query cache semantics under the hood
|
|
150
|
+
|
|
151
|
+
This is useful when you want model ownership and query-key identity without local persistence.
|
|
152
|
+
|
|
153
|
+
## 4. `$useStateLocal(...)`
|
|
154
|
+
|
|
155
|
+
Use this when the model state should persist in local storage.
|
|
156
|
+
|
|
157
|
+
Current-source characteristics:
|
|
158
|
+
|
|
159
|
+
- sync local storage persistence
|
|
160
|
+
- simplified storage keys by default
|
|
161
|
+
- `enabled: false`
|
|
162
|
+
- `staleTime: Infinity`
|
|
163
|
+
- state still flows through model-owned query cache first
|
|
164
|
+
|
|
165
|
+
A useful mental model is:
|
|
166
|
+
|
|
167
|
+
> local-storage state in Zova Model is not a separate store system. It is model-owned query state with a local-storage persister.
|
|
168
|
+
|
|
169
|
+
## 5. `$useStateCookie(...)`
|
|
170
|
+
|
|
171
|
+
Use this when the model state should persist in cookies.
|
|
172
|
+
|
|
173
|
+
Current-source characteristics:
|
|
174
|
+
|
|
175
|
+
- sync cookie persistence
|
|
176
|
+
- cookie-type coercion support such as `boolean`, `number`, `date`, or `string`
|
|
177
|
+
- simplified storage keys by default
|
|
178
|
+
- still uses model-owned query cache semantics
|
|
179
|
+
|
|
180
|
+
This is particularly relevant for state that must participate in request-aware or SSR-adjacent flows.
|
|
181
|
+
|
|
182
|
+
## 6. `$useStateDb(...)`
|
|
183
|
+
|
|
184
|
+
Use this when the model state should persist asynchronously in db-style client storage.
|
|
185
|
+
|
|
186
|
+
Current-source characteristics:
|
|
187
|
+
|
|
188
|
+
- async persistence through `localforage`
|
|
189
|
+
- `enabled: false`
|
|
190
|
+
- `staleTime: Infinity`
|
|
191
|
+
- explicit `ssr.dehydrate = false`
|
|
192
|
+
- getters may need async restore flow before data is available
|
|
193
|
+
|
|
194
|
+
This is useful for larger persisted client state that should outlive a page session without being stored in cookies or plain local storage.
|
|
195
|
+
|
|
196
|
+
## 7. `$useStateComputed(...)`
|
|
197
|
+
|
|
198
|
+
Use this when the model should expose derived state that is still model-key-oriented but computed locally.
|
|
199
|
+
|
|
200
|
+
Current-source characteristics:
|
|
201
|
+
|
|
202
|
+
- it prefixes the query key
|
|
203
|
+
- it memoizes the computed value by the hashed prefixed key
|
|
204
|
+
- it uses `$computed(...)` rather than TanStack Query fetching
|
|
205
|
+
|
|
206
|
+
## Query keys are model-owned, not global strings
|
|
207
|
+
|
|
208
|
+
One of the most important model-state behaviors is automatic key prefixing.
|
|
209
|
+
|
|
210
|
+
When a model uses:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
queryKey: ['list'];
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
that logical key is prefixed internally with model identity, and with selector when selector mode is enabled.
|
|
217
|
+
|
|
218
|
+
That means model code can use short business-facing keys while still getting namespace isolation.
|
|
219
|
+
|
|
220
|
+
## Persistence and restore behavior
|
|
221
|
+
|
|
222
|
+
Current source treats persistence as part of the model-state runtime.
|
|
223
|
+
|
|
224
|
+
Representative behaviors include:
|
|
225
|
+
|
|
226
|
+
- persisted data can be restored back into query state
|
|
227
|
+
- expired or busted persisted entries are removed automatically
|
|
228
|
+
- `defaultData` can initialize the cache when no restored value exists
|
|
229
|
+
- setting persisted state to `undefined` removes the persisted record
|
|
230
|
+
|
|
231
|
+
This is why model helpers are better understood as state-runtime helpers, not only convenience wrappers.
|
|
232
|
+
|
|
233
|
+
## SSR-sensitive state choices
|
|
234
|
+
|
|
235
|
+
Model state choices can affect SSR behavior.
|
|
236
|
+
|
|
237
|
+
Current-source behaviors to remember:
|
|
238
|
+
|
|
239
|
+
- query state can be dehydrated on server and hydrated on client
|
|
240
|
+
- mutations are not dehydrated
|
|
241
|
+
- `db` state is explicitly not dehydrated
|
|
242
|
+
- server cannot use local-storage or db persistence backends
|
|
243
|
+
- cookie state is special because cookie access can still exist through the app cookie surface
|
|
244
|
+
|
|
245
|
+
Practical implication:
|
|
246
|
+
|
|
247
|
+
- do not assume every persisted model state behaves the same during SSR
|
|
248
|
+
- choose `mem`, `local`, `cookie`, `db`, or `data` based on ownership and hydration requirements, not only convenience
|
|
249
|
+
|
|
250
|
+
## Real examples to read
|
|
251
|
+
|
|
252
|
+
### Minimal query and mutation model
|
|
253
|
+
|
|
254
|
+
Read:
|
|
255
|
+
|
|
256
|
+
- `zova/src/suite/a-demo/modules/demo-todo/src/model/todo.ts`
|
|
257
|
+
|
|
258
|
+
This file shows:
|
|
259
|
+
|
|
260
|
+
- extending `BeanModelBase`
|
|
261
|
+
- `@Model()` authoring
|
|
262
|
+
- query-style state through `$useStateData(...)`
|
|
263
|
+
- mutation-style state through `$useMutationData(...)`
|
|
264
|
+
- cache invalidation inside the model
|
|
265
|
+
|
|
266
|
+
### Selector-enabled cache-oriented model
|
|
267
|
+
|
|
268
|
+
Read:
|
|
269
|
+
|
|
270
|
+
- `zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts`
|
|
271
|
+
|
|
272
|
+
This file shows:
|
|
273
|
+
|
|
274
|
+
- `@Model({ enableSelector: true, ... })`
|
|
275
|
+
- richer model initialization in `__init__`
|
|
276
|
+
- mixed use of `$useStateMem(...)` and `$useStateDb(...)`
|
|
277
|
+
- model-owned tab state with cache and persistence decisions
|
|
278
|
+
|
|
279
|
+
### SSR-sensitive auth model
|
|
280
|
+
|
|
281
|
+
Read:
|
|
282
|
+
|
|
283
|
+
- `zova/src/suite/a-home/modules/home-passport/src/model/passport.ts`
|
|
284
|
+
|
|
285
|
+
This file shows:
|
|
286
|
+
|
|
287
|
+
- mixing `mem`, `local`, and `cookie` state in one model
|
|
288
|
+
- SSR-aware state choices
|
|
289
|
+
- model ownership of auth-related cached state and mutation flows
|
|
290
|
+
|
|
291
|
+
### Generic resource-owner model
|
|
292
|
+
|
|
293
|
+
Read:
|
|
294
|
+
|
|
295
|
+
- `zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts`
|
|
296
|
+
|
|
297
|
+
This file is especially important because it shows a higher-level infrastructure pattern rather than a small feature model.
|
|
298
|
+
|
|
299
|
+
It demonstrates that a model can act as a **resource owner facade** for CRUD-oriented business modules.
|
|
300
|
+
|
|
301
|
+
What this example shows:
|
|
302
|
+
|
|
303
|
+
- `@Model({ enableSelector: true })` uses selector to isolate one model instance per resource name
|
|
304
|
+
- `__init__(resource)` bootstraps resource metadata and resolves `resourceApi` before normal query usage
|
|
305
|
+
- `$computed(...)` can expose permissions, form provider, and schema surfaces as model-owned derived state
|
|
306
|
+
- `$useStateData(...)` drives select/view queries
|
|
307
|
+
- `$useMutationData(...)` is wrapped by reusable `create`, `update`, `delete`, and `mutationItem` helpers
|
|
308
|
+
- invalidation policy is centralized so list and item caches stay coherent after mutations
|
|
309
|
+
- model methods can combine `$fetch`, `$sdk`, OpenAPI schema helpers, and form-oriented helpers behind one reusable boundary
|
|
310
|
+
|
|
311
|
+
This is one of the best examples for understanding how Zova Model scales from simple data queries to reusable domain infrastructure.
|
|
312
|
+
|
|
313
|
+
If your next question is not only about the model class but about how generic routes, page shells, schema-driven blocks, and downstream CRUD blocks cooperate around that owner, continue with [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood).
|
|
314
|
+
|
|
315
|
+
#### Why `enableSelector` matters here
|
|
316
|
+
|
|
317
|
+
This model is not meant to represent only one concrete resource forever.
|
|
318
|
+
|
|
319
|
+
It is a reusable generic model class that can serve many resources.
|
|
320
|
+
|
|
321
|
+
That is why `enableSelector` is essential.
|
|
322
|
+
|
|
323
|
+
The model passes `resource` into `super.__init__(resource)`, so the resource name becomes the selector identity for that model instance.
|
|
324
|
+
|
|
325
|
+
At runtime, model query keys are therefore prefixed not only by the bean full name but also by the selected resource.
|
|
326
|
+
|
|
327
|
+
That means two consumers can both use logical keys such as:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
['select', '', hashkey(query)][('item', id, 'view')];
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
without colliding with each other, because the effective cache identity is separated by resource selector.
|
|
334
|
+
|
|
335
|
+
A practical reading takeaway is:
|
|
336
|
+
|
|
337
|
+
> selector turns one generic `ModelResource` implementation into many isolated resource-specific runtime instances.
|
|
338
|
+
|
|
339
|
+
#### Why this is a resource owner, not only a CRUD helper
|
|
340
|
+
|
|
341
|
+
A plain CRUD helper usually forwards requests.
|
|
342
|
+
|
|
343
|
+
`ModelResource` does more than that.
|
|
344
|
+
|
|
345
|
+
It owns several resource-level concerns together:
|
|
346
|
+
|
|
347
|
+
- bootstrap of resource metadata through `$QueryAutoLoad(...)`
|
|
348
|
+
- resolution of the final `resourceApi`
|
|
349
|
+
- permissions lookup
|
|
350
|
+
- OpenAPI schema access for view/create/update/select
|
|
351
|
+
- form integration such as submit mutation choice and default form data
|
|
352
|
+
- query and mutation cache invalidation rules
|
|
353
|
+
|
|
354
|
+
That is why this model is better understood as a **resource owner facade**.
|
|
355
|
+
|
|
356
|
+
In application code, prefer consuming that existing owner directly or adding a thin facade over it, while the lower-level `$fetch` and `$sdk` details stay inside the owner boundary.
|
|
357
|
+
|
|
358
|
+
#### How the cache-key design works
|
|
359
|
+
|
|
360
|
+
The cache-key design in this file is also worth reading carefully.
|
|
361
|
+
|
|
362
|
+
It separates three levels of identity:
|
|
363
|
+
|
|
364
|
+
- `keySelect(actionPath, query)` → list/query-level state
|
|
365
|
+
- `keyItemRoot(id)` → all state owned by one row id
|
|
366
|
+
- `keyItem(id, action)` → one concrete row action such as `view` or `update`
|
|
367
|
+
|
|
368
|
+
Representative shapes are:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
['select', actionPath ?? '', hashkey(query)][('item', id)][('item', id, action)];
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
This makes the invalidation strategy much clearer:
|
|
375
|
+
|
|
376
|
+
- create invalidates the select-level list cache
|
|
377
|
+
- update/delete invalidate the select-level list cache and the item root for that row
|
|
378
|
+
- item-specific queries such as `view(id)` live under the item branch
|
|
379
|
+
|
|
380
|
+
The practical benefit is that the model does not scatter cache policy across pages.
|
|
381
|
+
|
|
382
|
+
Instead, the model itself defines how list-level and row-level state stay coherent after mutations.
|
|
383
|
+
|
|
384
|
+
#### Why this example is a strong source-reading specimen
|
|
385
|
+
|
|
386
|
+
If `demo-todo` shows the minimal pattern for model queries and mutations, `rest-resource` shows the scalable pattern.
|
|
387
|
+
|
|
388
|
+
Use it when you want to understand how Zova Model can support:
|
|
389
|
+
|
|
390
|
+
- generic reusable business infrastructure
|
|
391
|
+
- selector-isolated model instances
|
|
392
|
+
- unified resource schema and permission ownership
|
|
393
|
+
- form-oriented integration on top of query state
|
|
394
|
+
- centralized invalidation semantics for larger UI systems
|
|
395
|
+
|
|
56
396
|
## Relationship to the server-data ladder
|
|
57
397
|
|
|
58
|
-
|
|
398
|
+
Think about the layers like this:
|
|
59
399
|
|
|
60
400
|
- `$fetch` → direct request access
|
|
61
401
|
- `$api` → business-oriented service methods
|
|
62
|
-
- `Model` → cached, reusable,
|
|
402
|
+
- `Model` → cached, reusable, persistence-aware state
|
|
63
403
|
|
|
64
404
|
That makes the model layer one of the most important bridges between backend contracts and frontend rendering.
|
|
65
405
|
|
|
66
|
-
##
|
|
406
|
+
## Practical design checks
|
|
407
|
+
|
|
408
|
+
When adding frontend state, avoid jumping straight to ad hoc request logic or generic store habits.
|
|
409
|
+
|
|
410
|
+
Instead ask:
|
|
411
|
+
|
|
412
|
+
1. should this state live in an existing model?
|
|
413
|
+
2. should it be `data`, `mem`, `local`, `cookie`, or `db` state?
|
|
414
|
+
3. should the model own invalidation or refetch behavior?
|
|
415
|
+
4. does persistence or SSR change the right helper choice?
|
|
416
|
+
5. should the page/controller consume a model instead of owning this state directly?
|
|
417
|
+
|
|
418
|
+
That usually produces cleaner, more Cabloy-native code.
|
|
419
|
+
|
|
420
|
+
## Final takeaway
|
|
421
|
+
|
|
422
|
+
The most important usage insight is simple:
|
|
67
423
|
|
|
68
|
-
|
|
424
|
+
> In Zova, model state is not only “fetch some data”. It is a unified model-owned runtime for query state, local state, persistence, invalidation, and SSR-aware reuse.
|
|
69
425
|
|
|
70
|
-
|
|
426
|
+
Once that is clear, the helper family in `a-model` reads as one coherent system instead of several unrelated APIs.
|
|
@@ -40,11 +40,11 @@ These categories make module resources discoverable and consistently organized.
|
|
|
40
40
|
Representative CLI entrypoints include:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
npm run zova :init:config
|
|
44
|
-
npm run zova :init:constant
|
|
45
|
-
npm run zova :init:locale
|
|
46
|
-
npm run zova :init:error
|
|
47
|
-
npm run zova :create:bean api test -- --module=
|
|
43
|
+
npm run zova :init:config training-student
|
|
44
|
+
npm run zova :init:constant training-student
|
|
45
|
+
npm run zova :init:locale training-student
|
|
46
|
+
npm run zova :init:error training-student
|
|
47
|
+
npm run zova :create:bean api test -- --module=training-student
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
This matters because scope is not just a read surface. It is the organized destination for resources generated or initialized through the standard Zova workflow.
|
|
@@ -119,14 +119,14 @@ Representative pattern:
|
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
121
|
@UseScope()
|
|
122
|
-
$$
|
|
122
|
+
$$scopeTrainingStudent: ScopeModuleTrainingStudent;
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
A common follow-up access pattern is:
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
|
-
const res = await this.$$
|
|
129
|
-
console.log(this.$$
|
|
128
|
+
const res = await this.$$scopeTrainingStudent.api.test.echo();
|
|
129
|
+
console.log(this.$$scopeTrainingStudent.locale.HelloWorld());
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
This allows one module to consume another module’s scoped resources explicitly without flattening everything into one shared global namespace.
|
|
@@ -129,7 +129,7 @@ Representative patterns include:
|
|
|
129
129
|
|
|
130
130
|
```json
|
|
131
131
|
{
|
|
132
|
-
"name": "zova-module-
|
|
132
|
+
"name": "zova-module-training-student",
|
|
133
133
|
"zovaModule": {
|
|
134
134
|
"dependencies": {
|
|
135
135
|
"a-zova": "5.0.0"
|
|
@@ -160,6 +160,7 @@ This reinforces that modules are not merely folders. They are explicit package,
|
|
|
160
160
|
|
|
161
161
|
Read this together with:
|
|
162
162
|
|
|
163
|
+
- [Suites and Modules](/fullstack/suites-and-modules) for the cross-stack suite-first decision path in the monorepo
|
|
163
164
|
- [IoC and Beans](/frontend/ioc-and-beans)
|
|
164
165
|
- [Module Scope](/frontend/module-scope)
|
|
165
166
|
- [Frontend Scripts](/frontend/scripts)
|
|
@@ -66,3 +66,10 @@ When changing auth-sensitive routing behavior, ask:
|
|
|
66
66
|
4. should redirects happen at the routing-policy layer rather than being hardcoded into page logic?
|
|
67
67
|
|
|
68
68
|
That produces cleaner and more framework-native navigation behavior.
|
|
69
|
+
|
|
70
|
+
## Where to read next
|
|
71
|
+
|
|
72
|
+
- If you want the broader route-record surface first, continue with [Page Route Guide](/frontend/page-route-guide).
|
|
73
|
+
- If the guard decision depends on route metadata or task-level shell state, continue with [Page Meta Guide](/frontend/page-meta-guide).
|
|
74
|
+
- If the guard behavior is really part of a larger SSR decision path, continue with [SSR Architecture Overview](/frontend/ssr-architecture-overview).
|
|
75
|
+
- If you want the deeper routing runtime after the public policy surface is clear, descend into [Zova Router Under the Hood](/frontend/zova-router-under-the-hood).
|
|
@@ -20,22 +20,29 @@ For the bridge view, also see [Backend OpenAPI to Frontend SDK](/fullstack/opena
|
|
|
20
20
|
|
|
21
21
|
For the broader frontend contract-consumption ladder, also see [Server Data](/frontend/server-data), [API Schema Guide](/frontend/api-schema-guide), and [SDK Guide](/frontend/sdk-guide).
|
|
22
22
|
|
|
23
|
+
If your next question is how the lower-level OpenAPI/schema runtime works under `$sdk`, continue with [A-OpenAPI Under the Hood](/frontend/a-openapi-under-the-hood).
|
|
24
|
+
|
|
25
|
+
If your next question is how generated contract material becomes schema-driven frontend behavior or resource-owner consumption, continue with [API Schema Guide](/frontend/api-schema-guide) and [ModelResource Internals Deep Dive](/frontend/model-resource-internals-deep-dive).
|
|
26
|
+
|
|
23
27
|
## Initialize OpenAPI config
|
|
24
28
|
|
|
25
|
-
Example: initialize OpenAPI config for module `
|
|
29
|
+
Example: initialize OpenAPI config for module `training-student`.
|
|
26
30
|
|
|
27
31
|
```bash
|
|
28
|
-
npm run zova :openapi:config
|
|
32
|
+
npm run zova :openapi:config training-student
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
## Module-level config
|
|
32
36
|
|
|
33
|
-
Each module
|
|
37
|
+
Each module must explicitly declare which backend operations belong to it.
|
|
34
38
|
|
|
35
39
|
Representative idea:
|
|
36
40
|
|
|
37
|
-
- configure
|
|
41
|
+
- configure `operations.match` or `operations.ignore` in the module OpenAPI config
|
|
38
42
|
- keep API ownership aligned with the module boundary
|
|
43
|
+
- avoid generating large amounts of unrelated SDK output for the current module
|
|
44
|
+
|
|
45
|
+
If both `operations.match` and `operations.ignore` are left empty, `:openapi:generate` should fail fast and ask you to define one of them explicitly. This fail-fast feedback helps both developers and AI agents notice the missing ownership rule immediately and correct it before unrelated SDK output is generated.
|
|
39
46
|
|
|
40
47
|
This modular split matters because Cabloy does not treat the frontend as one flat API client surface.
|
|
41
48
|
|
|
@@ -50,10 +57,10 @@ Representative use case:
|
|
|
50
57
|
|
|
51
58
|
## Generate the SDK
|
|
52
59
|
|
|
53
|
-
Example: generate OpenAPI-based frontend services for module `
|
|
60
|
+
Example: generate OpenAPI-based frontend services for module `training-student`.
|
|
54
61
|
|
|
55
62
|
```bash
|
|
56
|
-
npm run zova :openapi:generate
|
|
63
|
+
npm run zova :openapi:generate training-student
|
|
57
64
|
```
|
|
58
65
|
|
|
59
66
|
## Build the rest-contract output
|
|
@@ -90,6 +97,10 @@ If the backend contract itself changes, first inspect or update the backend cont
|
|
|
90
97
|
|
|
91
98
|
Then return to this page for the frontend regeneration step.
|
|
92
99
|
|
|
100
|
+
If your next question is what that generated contract looks like when it is actually consumed in a practical frontend path, continue with [Generated Contract Consumption Specimen](/frontend/generated-contract-consumption-specimen).
|
|
101
|
+
|
|
102
|
+
If you then want a proof-oriented or symptom-first companion for the consumer-side path, continue with [Generated Contract Consumption Verify Playbook](/frontend/generated-contract-consumption-verify-playbook) and [Generated Contract Consumption Debug Checklist](/frontend/generated-contract-consumption-debug-checklist).
|
|
103
|
+
|
|
93
104
|
## Implementation checks for SDK regeneration decisions
|
|
94
105
|
|
|
95
106
|
When evaluating a request that depends on backend contracts, ask:
|
|
@@ -17,10 +17,10 @@ That combination is one of the clearest examples of Zova’s overall design phil
|
|
|
17
17
|
|
|
18
18
|
## Create a page
|
|
19
19
|
|
|
20
|
-
Example: create a page named `counter` in module `
|
|
20
|
+
Example: create a page named `counter` in module `training-student`.
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
npm run zova :create:page counter -- --module=
|
|
23
|
+
npm run zova :create:page counter -- --module=training-student
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## Route path generation
|
|
@@ -29,9 +29,9 @@ Zova automatically derives the page path from the module and page names.
|
|
|
29
29
|
|
|
30
30
|
Representative example:
|
|
31
31
|
|
|
32
|
-
- module: `
|
|
32
|
+
- module: `training-student`
|
|
33
33
|
- page: `counter`
|
|
34
|
-
- generated page path: `/
|
|
34
|
+
- generated page path: `/training/student/counter`
|
|
35
35
|
|
|
36
36
|
This matters because the framework already has conventions for route structure. AI should reuse those conventions rather than inventing unrelated paths.
|
|
37
37
|
|
|
@@ -123,7 +123,7 @@ A typical first step is keeping the page controller responsible for state while
|
|
|
123
123
|
#### Create the first render bean
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
npm run zova :refactor:firstRender page/counter -- --module=
|
|
126
|
+
npm run zova :refactor:firstRender page/counter -- --module=training-student
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
Representative render bean shape:
|
|
@@ -146,7 +146,7 @@ class RenderPageCounter extends BeanRenderBase {
|
|
|
146
146
|
#### Create the first style bean
|
|
147
147
|
|
|
148
148
|
```bash
|
|
149
|
-
npm run zova :refactor:firstStyle page/counter -- --module=
|
|
149
|
+
npm run zova :refactor:firstStyle page/counter -- --module=training-student
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
Representative style bean shape:
|
|
@@ -177,19 +177,19 @@ Representative refactors include:
|
|
|
177
177
|
#### Create another render bean
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
|
-
npm run zova :refactor:anotherRender page/counter another -- --module=
|
|
180
|
+
npm run zova :refactor:anotherRender page/counter another -- --module=training-student
|
|
181
181
|
```
|
|
182
182
|
|
|
183
183
|
#### Create another style bean
|
|
184
184
|
|
|
185
185
|
```bash
|
|
186
|
-
npm run zova :refactor:anotherStyle page/counter another -- --module=
|
|
186
|
+
npm run zova :refactor:anotherStyle page/counter another -- --module=training-student
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
#### Create a service bean for state management
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
|
-
npm run zova :create:bean service page/counter/counter -- --module=
|
|
192
|
+
npm run zova :create:bean service page/counter/counter -- --module=training-student
|
|
193
193
|
```
|
|
194
194
|
|
|
195
195
|
Representative service bean shape:
|
|
@@ -215,6 +215,12 @@ These refactors are supported by Zova CLI commands rather than requiring a fully
|
|
|
215
215
|
|
|
216
216
|
When generating or editing a Zova page, preserve the page/controller mental model instead of rewriting the code into a generic Vue single-file-component pattern.
|
|
217
217
|
|
|
218
|
+
If you want a stronger reading bridge from Vue habits into page-controller source code, also read:
|
|
219
|
+
|
|
220
|
+
- [Reading Zova for Vue Developers](/frontend/reading-zova-for-vue-developers)
|
|
221
|
+
- [Zova Reactivity Under the Hood](/frontend/zova-reactivity-under-the-hood)
|
|
222
|
+
- [Zova Source Reading Map](/frontend/zova-source-reading-map)
|
|
223
|
+
|
|
218
224
|
A better default is:
|
|
219
225
|
|
|
220
226
|
1. use the Zova page generator
|