cabloy 5.1.59 → 5.1.61
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/references/follow-up-checklist.md +1 -0
- package/.claude/skills/cabloy-contract-loop/SKILL.md +103 -14
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +126 -12
- package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +148 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +49 -13
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +11 -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 +274 -0
- package/.claude/skills/cabloy-resource-field-update/evals/evals.json +53 -0
- package/.claude/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +102 -0
- package/.claude/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +120 -0
- package/.claude/skills/cabloy-resource-field-update/references/follow-up-checklist.md +80 -0
- package/.claude/skills/cabloy-resource-field-update/references/verification-checklist.md +97 -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/.github/workflows/docs-pages.yml +2 -0
- package/.github/workflows/vona-cov-pg.yml +2 -0
- package/.github/workflows/vona-test-crud.yml +4 -2
- package/.github/workflows/vona-test-mysql.yml +2 -0
- package/.github/workflows/vona-test-pg.yml +2 -0
- package/.github/workflows/vona-test-sqlite3.yml +2 -0
- package/.github/workflows/vona-tsc.yml +2 -0
- package/.github/workflows/zova-ui.yml +2 -0
- package/.gitignore +0 -4
- package/CHANGELOG.md +52 -0
- package/CLAUDE.md +12 -0
- package/README.md +15 -0
- package/cabloy-docs/.vitepress/config.mjs +89 -0
- package/cabloy-docs/ai/class-placement-rule.md +2 -0
- package/cabloy-docs/ai/cli-to-skill-map.md +14 -0
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +14 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +27 -9
- 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 +11 -0
- package/cabloy-docs/backend/bean-scene-authoring.md +350 -0
- package/cabloy-docs/backend/cli.md +26 -1
- package/cabloy-docs/backend/dto-guide.md +6 -0
- package/cabloy-docs/backend/entity-guide.md +18 -0
- package/cabloy-docs/backend/foundation.md +28 -3
- package/cabloy-docs/backend/introduction.md +10 -0
- package/cabloy-docs/backend/serialization-guide.md +10 -0
- package/cabloy-docs/backend/service-guide.md +2 -0
- package/cabloy-docs/backend/status-guide.md +271 -0
- package/cabloy-docs/backend/websocket-call-flow.md +435 -0
- package/cabloy-docs/backend/websocket-guide.md +455 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +381 -0
- package/cabloy-docs/backend/websocket-usage-guide.md +356 -0
- package/cabloy-docs/frontend/api-guide.md +2 -0
- package/cabloy-docs/frontend/bean-scene-authoring.md +374 -0
- package/cabloy-docs/frontend/behavior-guide.md +449 -0
- package/cabloy-docs/frontend/cli.md +24 -0
- package/cabloy-docs/frontend/command-scene-authoring.md +495 -0
- package/cabloy-docs/frontend/design-principles.md +6 -0
- package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
- package/cabloy-docs/frontend/form-guide.md +795 -0
- package/cabloy-docs/frontend/foundation.md +29 -0
- package/cabloy-docs/frontend/introduction.md +17 -1
- package/cabloy-docs/frontend/ioc-and-beans.md +16 -9
- package/cabloy-docs/frontend/mock-guide.md +1 -0
- package/cabloy-docs/frontend/model-architecture.md +252 -39
- package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
- package/cabloy-docs/frontend/model-resource-cookbook.md +505 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +382 -0
- package/cabloy-docs/frontend/model-resource-usage-guide.md +318 -0
- package/cabloy-docs/frontend/model-state-guide.md +366 -13
- package/cabloy-docs/frontend/openapi-sdk-guide.md +5 -2
- package/cabloy-docs/frontend/page-guide.md +6 -0
- package/cabloy-docs/frontend/quickstart.md +4 -0
- package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
- package/cabloy-docs/frontend/router-tabs-admin-web-comparison.md +206 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +106 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +469 -0
- package/cabloy-docs/frontend/router-tabs-overview.md +227 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +343 -0
- package/cabloy-docs/frontend/server-data.md +2 -0
- package/cabloy-docs/frontend/ssr-architecture-overview.md +211 -0
- package/cabloy-docs/frontend/ssr-build-deploy-guide.md +308 -0
- package/cabloy-docs/frontend/ssr-review-checklist.md +184 -0
- package/cabloy-docs/frontend/ssr-troubleshooting-guide.md +301 -0
- package/cabloy-docs/frontend/zova-form-source-reading-map.md +295 -0
- package/cabloy-docs/frontend/zova-form-under-the-hood.md +556 -0
- package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
- package/cabloy-docs/frontend/zova-source-reading-map.md +327 -0
- package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
- package/cabloy-docs/fullstack/contract-loop-playbook.md +350 -0
- package/cabloy-docs/fullstack/framework-performance.md +3 -3
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +44 -1
- package/cabloy-docs/fullstack/introduction.md +40 -0
- package/cabloy-docs/fullstack/openapi-to-sdk.md +19 -9
- package/cabloy-docs/fullstack/quickstart.md +7 -1
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +111 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +122 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +131 -0
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +144 -0
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +146 -0
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +170 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +192 -0
- package/cabloy-docs/index.md +4 -3
- package/cabloy-docs/reference/bean-scene-boilerplates.md +75 -0
- package/cabloy-docs/reference/cli-reference.md +2 -0
- package/package.json +7 -2
- package/scripts/initTestData.ts +25 -0
- package/scripts/upgrade.ts +17 -2
- package/vona/packages-cli/cabloy-cli/package.json +2 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/cli.create.module.ts +4 -0
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +226 -1091
- package/vona/pnpm-workspace.yaml +0 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/assets/static/img/vona.svg +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/package.original.json +1 -1
- package/zova/packages-cli/cli/package.json +3 -3
- package/zova/packages-cli/cli-set-front/cli/templates/init/icon/boilerplate/icons/default/zova.svg +1 -1
- 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 +3 -3
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.create.module.ts +4 -0
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
- package/zova/packages-cli/cli-set-front/src/lib/command/create.bean.ts +5 -1
- package/zova/packages-utils/zova-vite/package.json +2 -2
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +282 -1311
- package/zova/pnpm-workspace.yaml +0 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/cabloy.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/vona.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/zova.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/src/.metadata/icons/groups/social.svg +3 -3
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +9 -0
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +66 -16
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-routertabs/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts +60 -18
- package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableActionRow/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableCell/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Zova vs Vue 3 Comparison
|
|
2
|
+
|
|
3
|
+
This page compares **Zova’s frontend programming model** with the **default mental model many developers bring from Vue 3**.
|
|
4
|
+
|
|
5
|
+
The goal is not to argue that one replaces the other.
|
|
6
|
+
|
|
7
|
+
The goal is to explain two things clearly:
|
|
8
|
+
|
|
9
|
+
1. **Zova still stands on top of Vue 3 runtime and reactivity foundations**
|
|
10
|
+
2. **Zova deliberately changes the preferred authoring surface, architectural center, and code-organization habits built on top of those foundations**
|
|
11
|
+
|
|
12
|
+
Use this page together with:
|
|
13
|
+
|
|
14
|
+
- [Reading Zova for Vue Developers](/frontend/reading-zova-for-vue-developers)
|
|
15
|
+
- [Zova Reactivity Under the Hood](/frontend/zova-reactivity-under-the-hood)
|
|
16
|
+
- [Zova Source Reading Map](/frontend/zova-source-reading-map)
|
|
17
|
+
|
|
18
|
+
## Why this page exists
|
|
19
|
+
|
|
20
|
+
A Vue developer can look at Zova code and ask questions like these:
|
|
21
|
+
|
|
22
|
+
- why is this state a plain class field instead of a `ref`?
|
|
23
|
+
- why is derived state wired in `__init__` instead of declared in `setup()`?
|
|
24
|
+
- why does route state appear on the controller instance instead of being pulled through `useRoute()`?
|
|
25
|
+
- why does the page grow into controller/render/style/service beans instead of only more composables and child components?
|
|
26
|
+
|
|
27
|
+
Those questions are reasonable.
|
|
28
|
+
|
|
29
|
+
This page answers them by comparing the two programming models across a few stable architectural dimensions.
|
|
30
|
+
|
|
31
|
+
## The shortest accurate summary
|
|
32
|
+
|
|
33
|
+
If you only want the shortest answer, use this one:
|
|
34
|
+
|
|
35
|
+
> Vue 3 usually presents reactivity as explicit local primitives and composition-oriented setup logic, while Zova presents reactivity through framework-managed bean instances and controller-oriented architecture.
|
|
36
|
+
|
|
37
|
+
Under the surface, Zova still uses Vue runtime/reactivity capabilities.
|
|
38
|
+
|
|
39
|
+
The big difference is the **business-facing programming model**.
|
|
40
|
+
|
|
41
|
+
## Side-by-side comparison table
|
|
42
|
+
|
|
43
|
+
| Dimension | Zova | Vue 3 default mental model |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| Reactive host | controller or bean instance | local `ref` / `reactive` values inside `setup()` |
|
|
46
|
+
| Derived state | `$computed()` often assigned to instance fields | `computed()` usually assigned to local variables |
|
|
47
|
+
| Main wiring surface | `__init__` and bean lifecycle | `setup()` and composition hooks |
|
|
48
|
+
| Route state access | page-controller surface such as `$route`, `$params`, `$query` | composables such as `useRoute()` |
|
|
49
|
+
| Sharing model | IoC containers and bean scopes unify more sharing patterns | composables, props/emits, `provide/inject`, and store layers often coexist |
|
|
50
|
+
| Render organization | controller-oriented; render can stay in controller or move to render beans | component-oriented; template/render/setup stay the obvious center |
|
|
51
|
+
| Growth path | split into controller, render, style, service, model, or other beans | split into composables, child components, and store or helper layers |
|
|
52
|
+
| Architectural emphasis | explicit object roles, scope ownership, and runtime-managed surfaces | flexible local composition with more developer-managed assembly |
|
|
53
|
+
|
|
54
|
+
## 1. Reactive host
|
|
55
|
+
|
|
56
|
+
### Zova
|
|
57
|
+
|
|
58
|
+
Zova often makes the controller or bean instance the visible reactive surface.
|
|
59
|
+
|
|
60
|
+
That is why code can look like:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
count: number = 0;
|
|
64
|
+
|
|
65
|
+
increment() {
|
|
66
|
+
this.count++;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The important idea is not only shorter syntax.
|
|
71
|
+
|
|
72
|
+
The important idea is that the framework is making the bean instance itself the business-facing state host.
|
|
73
|
+
|
|
74
|
+
### Vue 3
|
|
75
|
+
|
|
76
|
+
The default Vue mental model usually starts with explicit primitives:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const count = ref(0);
|
|
80
|
+
|
|
81
|
+
function increment() {
|
|
82
|
+
count.value++;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Comparison takeaway
|
|
87
|
+
|
|
88
|
+
- Vue 3 teaches you to build reactivity from visible primitives
|
|
89
|
+
- Zova teaches you to work on top of a framework-managed reactive object
|
|
90
|
+
|
|
91
|
+
## 2. Derived state
|
|
92
|
+
|
|
93
|
+
### Zova
|
|
94
|
+
|
|
95
|
+
Derived state often looks like instance wiring:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
protected async __init__() {
|
|
99
|
+
this.count2 = this.$computed(() => {
|
|
100
|
+
return `=== ${this.count} ===`;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This makes derived state feel like part of object initialization and lifecycle wiring.
|
|
106
|
+
|
|
107
|
+
### Vue 3
|
|
108
|
+
|
|
109
|
+
Derived state often looks like local reactive declaration:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const count2 = computed(() => `=== ${count.value} ===`);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Comparison takeaway
|
|
116
|
+
|
|
117
|
+
- Vue 3 presents derived state as a local reactive value
|
|
118
|
+
- Zova often presents it as an instance-level property of a controller or bean
|
|
119
|
+
|
|
120
|
+
## 3. Main wiring surface
|
|
121
|
+
|
|
122
|
+
### Zova
|
|
123
|
+
|
|
124
|
+
Zova concentrates many setup concerns inside bean lifecycle methods such as:
|
|
125
|
+
|
|
126
|
+
- `__init__`
|
|
127
|
+
- `__dispose__`
|
|
128
|
+
|
|
129
|
+
That is where you often wire:
|
|
130
|
+
|
|
131
|
+
- computed values
|
|
132
|
+
- watchers
|
|
133
|
+
- derived state
|
|
134
|
+
- lifecycle cleanup
|
|
135
|
+
|
|
136
|
+
### Vue 3
|
|
137
|
+
|
|
138
|
+
Vue 3 usually treats `setup()` as the main assembly point, then uses composition hooks around it.
|
|
139
|
+
|
|
140
|
+
### Comparison takeaway
|
|
141
|
+
|
|
142
|
+
- Vue 3 is more obviously composition-function-centered
|
|
143
|
+
- Zova is more obviously lifecycle-and-object-centered
|
|
144
|
+
|
|
145
|
+
## 4. Route state access
|
|
146
|
+
|
|
147
|
+
### Zova
|
|
148
|
+
|
|
149
|
+
For page controllers, route-aware state is often part of the controller surface:
|
|
150
|
+
|
|
151
|
+
- `$route`
|
|
152
|
+
- `$params`
|
|
153
|
+
- `$query`
|
|
154
|
+
|
|
155
|
+
This keeps route-aware page logic close to the page controller itself.
|
|
156
|
+
|
|
157
|
+
### Vue 3
|
|
158
|
+
|
|
159
|
+
Vue code more often pulls route state through:
|
|
160
|
+
|
|
161
|
+
- `useRoute()`
|
|
162
|
+
- `useRouter()`
|
|
163
|
+
|
|
164
|
+
### Comparison takeaway
|
|
165
|
+
|
|
166
|
+
- Vue 3 usually pulls route state into local composition code
|
|
167
|
+
- Zova usually pushes route-aware state into the page-controller surface
|
|
168
|
+
|
|
169
|
+
## 5. Sharing model
|
|
170
|
+
|
|
171
|
+
### Zova
|
|
172
|
+
|
|
173
|
+
Zova uses IoC as a larger frontend architectural answer, not only as a small dependency-injection convenience.
|
|
174
|
+
|
|
175
|
+
That means questions often become:
|
|
176
|
+
|
|
177
|
+
- which bean owns this behavior?
|
|
178
|
+
- which scope should this bean live in?
|
|
179
|
+
- should this be resolved through injection or lookup?
|
|
180
|
+
|
|
181
|
+
### Vue 3
|
|
182
|
+
|
|
183
|
+
Vue projects often combine several distinct sharing tools depending on the team and codebase:
|
|
184
|
+
|
|
185
|
+
- props and emits
|
|
186
|
+
- composables
|
|
187
|
+
- `provide/inject`
|
|
188
|
+
- store layers
|
|
189
|
+
|
|
190
|
+
### Comparison takeaway
|
|
191
|
+
|
|
192
|
+
- Vue 3 gives a flexible base that can lead to multiple sharing styles in one codebase
|
|
193
|
+
- Zova tries to unify more of those patterns through bean and scope architecture
|
|
194
|
+
|
|
195
|
+
## 6. Render organization
|
|
196
|
+
|
|
197
|
+
### Zova
|
|
198
|
+
|
|
199
|
+
Zova treats render as part of a controller-oriented architecture.
|
|
200
|
+
|
|
201
|
+
A page can:
|
|
202
|
+
|
|
203
|
+
- render directly inside the controller
|
|
204
|
+
- later split render into a dedicated render bean
|
|
205
|
+
- also split style into a style bean
|
|
206
|
+
- later move additional state or behavior into service beans
|
|
207
|
+
|
|
208
|
+
### Vue 3
|
|
209
|
+
|
|
210
|
+
Vue usually treats the component itself as the natural render center:
|
|
211
|
+
|
|
212
|
+
- template
|
|
213
|
+
- render function
|
|
214
|
+
- `setup()` locals feeding the component render
|
|
215
|
+
|
|
216
|
+
### Comparison takeaway
|
|
217
|
+
|
|
218
|
+
- Vue 3 makes the component the obvious render center
|
|
219
|
+
- Zova makes the page or component controller architecture the larger center
|
|
220
|
+
|
|
221
|
+
## 7. Growth path as complexity increases
|
|
222
|
+
|
|
223
|
+
### Zova
|
|
224
|
+
|
|
225
|
+
A common Zova growth path is:
|
|
226
|
+
|
|
227
|
+
1. start with one page controller
|
|
228
|
+
2. split render into a render bean
|
|
229
|
+
3. split style into a style bean
|
|
230
|
+
4. extract state or logic into service or model beans when ownership becomes clearer
|
|
231
|
+
|
|
232
|
+
### Vue 3
|
|
233
|
+
|
|
234
|
+
A common Vue growth path is:
|
|
235
|
+
|
|
236
|
+
1. start with one component
|
|
237
|
+
2. extract composables
|
|
238
|
+
3. add child components
|
|
239
|
+
4. introduce or extend store ownership where needed
|
|
240
|
+
|
|
241
|
+
### Comparison takeaway
|
|
242
|
+
|
|
243
|
+
- Vue 3 complexity growth often feels more composition-first
|
|
244
|
+
- Zova complexity growth often feels more role-and-boundary-first
|
|
245
|
+
|
|
246
|
+
## 8. Code-reading experience
|
|
247
|
+
|
|
248
|
+
### Zova
|
|
249
|
+
|
|
250
|
+
When reading Zova, you often ask:
|
|
251
|
+
|
|
252
|
+
- which bean am I looking at?
|
|
253
|
+
- is this a page, component, service, model, render, or style role?
|
|
254
|
+
- what scope owns this bean?
|
|
255
|
+
- what runtime surface is being injected or refreshed onto it?
|
|
256
|
+
|
|
257
|
+
### Vue 3
|
|
258
|
+
|
|
259
|
+
When reading Vue, you often ask:
|
|
260
|
+
|
|
261
|
+
- what lives in `setup()`?
|
|
262
|
+
- which composables are being used?
|
|
263
|
+
- which local refs/computeds feed the render?
|
|
264
|
+
- where does state ownership move to a store or parent component?
|
|
265
|
+
|
|
266
|
+
### Comparison takeaway
|
|
267
|
+
|
|
268
|
+
The reading rhythm itself changes.
|
|
269
|
+
|
|
270
|
+
That is why a Vue expert can still feel unfamiliar inside Zova at first even though the lower-level reactive runtime is related.
|
|
271
|
+
|
|
272
|
+
## What is the same underneath
|
|
273
|
+
|
|
274
|
+
Despite all the differences above, a few important foundations are still shared:
|
|
275
|
+
|
|
276
|
+
- Vue reactivity still matters underneath
|
|
277
|
+
- dependency tracking still matters underneath
|
|
278
|
+
- recomputation and rerender still matter underneath
|
|
279
|
+
- component runtime behavior still matters underneath
|
|
280
|
+
|
|
281
|
+
So the comparison is **not**:
|
|
282
|
+
|
|
283
|
+
- Zova versus Vue runtime
|
|
284
|
+
|
|
285
|
+
It is mostly:
|
|
286
|
+
|
|
287
|
+
- Zova’s architectural authoring model versus Vue’s default authoring habits
|
|
288
|
+
|
|
289
|
+
## When to prefer this comparison page
|
|
290
|
+
|
|
291
|
+
Use this page when:
|
|
292
|
+
|
|
293
|
+
- you already know Vue and want a clean translation layer into Zova
|
|
294
|
+
- you want one page that summarizes the biggest architectural differences quickly
|
|
295
|
+
- you need to explain to another developer why Zova code should not be auto-refactored back toward generic Vue patterns
|
|
296
|
+
|
|
297
|
+
If you want the next level of detail after this page, continue with:
|
|
298
|
+
|
|
299
|
+
- [Zova Reactivity Under the Hood](/frontend/zova-reactivity-under-the-hood)
|
|
300
|
+
- [Zova Source Reading Map](/frontend/zova-source-reading-map)
|
|
301
|
+
|
|
302
|
+
## Final takeaway
|
|
303
|
+
|
|
304
|
+
The most important comparison insight is simple:
|
|
305
|
+
|
|
306
|
+
> Vue 3 usually teaches explicit reactive primitives first and architectural composition second. Zova keeps the Vue runtime foundation but teaches explicit architectural roles first and hides more of the reactive primitive management behind framework-managed controller and bean surfaces.
|
|
307
|
+
|
|
308
|
+
Once that shift is clear, Zova code becomes much easier to read on its own terms.
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Contract Loop Playbook
|
|
2
|
+
|
|
3
|
+
This page is the canonical playbook for Cabloy’s bidirectional fullstack contract loop.
|
|
4
|
+
|
|
5
|
+
Use it when you need to decide:
|
|
6
|
+
|
|
7
|
+
- where source truth lives for a change
|
|
8
|
+
- which generated handoff should be refreshed
|
|
9
|
+
- which side is actually stale
|
|
10
|
+
- whether the problem is source drift, generated-output drift, consumer drift, or local dependency drift
|
|
11
|
+
|
|
12
|
+
## Why this playbook exists
|
|
13
|
+
|
|
14
|
+
Cabloy’s fullstack collaboration is not only backend-to-frontend.
|
|
15
|
+
|
|
16
|
+
The same monorepo supports two symmetric chains:
|
|
17
|
+
|
|
18
|
+
- **forward chain** — backend contract emission and frontend consumption
|
|
19
|
+
- **reverse chain** — frontend metadata or resource handoff and backend consumption
|
|
20
|
+
|
|
21
|
+
The core model applies to both **Cabloy Basic** and **Cabloy Start**.
|
|
22
|
+
|
|
23
|
+
What changes by edition is not the model itself, but the operational branch:
|
|
24
|
+
|
|
25
|
+
- flavor names
|
|
26
|
+
- UI-resource examples
|
|
27
|
+
- generated-output paths
|
|
28
|
+
- build commands
|
|
29
|
+
|
|
30
|
+
So the first question is always:
|
|
31
|
+
|
|
32
|
+
1. which chain am I in?
|
|
33
|
+
2. which edition is active?
|
|
34
|
+
|
|
35
|
+
## Shared vocabulary
|
|
36
|
+
|
|
37
|
+
Use these terms consistently:
|
|
38
|
+
|
|
39
|
+
- **contract loop** — the full bidirectional Vona↔Zova collaboration model
|
|
40
|
+
- **forward chain** — backend contract truth flows into generated frontend consumers
|
|
41
|
+
- **reverse chain** — frontend-owned metadata or resources flow into backend consumers
|
|
42
|
+
- **contract source** — the authored layer that currently owns truth
|
|
43
|
+
- **generated handoff** — the generated output that carries truth to the other side
|
|
44
|
+
- **consumer drift** — downstream consumers no longer match current truth
|
|
45
|
+
- **local dependency drift** — generated artifacts are already correct, but installed local file dependencies are still stale
|
|
46
|
+
|
|
47
|
+
## The two chains
|
|
48
|
+
|
|
49
|
+
### Forward chain
|
|
50
|
+
|
|
51
|
+
Use the forward chain when backend-authored contract surfaces changed.
|
|
52
|
+
|
|
53
|
+
Typical contract sources:
|
|
54
|
+
|
|
55
|
+
- controller request or response signatures
|
|
56
|
+
- DTOs
|
|
57
|
+
- entity field metadata
|
|
58
|
+
- validation rules
|
|
59
|
+
- OpenAPI metadata
|
|
60
|
+
|
|
61
|
+
Typical handoff:
|
|
62
|
+
|
|
63
|
+
- Swagger or OpenAPI output
|
|
64
|
+
- generated Zova SDK or schema-aware helpers
|
|
65
|
+
- flavor-built REST output when the workflow depends on it
|
|
66
|
+
|
|
67
|
+
Typical consumers:
|
|
68
|
+
|
|
69
|
+
- generated frontend API files
|
|
70
|
+
- thin frontend model facades
|
|
71
|
+
- schema-driven UI
|
|
72
|
+
- custom row or page actions
|
|
73
|
+
|
|
74
|
+
### Reverse chain
|
|
75
|
+
|
|
76
|
+
Use the reverse chain when frontend-owned metadata or resources changed and backend-side tooling or metadata will consume them.
|
|
77
|
+
|
|
78
|
+
Typical contract sources:
|
|
79
|
+
|
|
80
|
+
- frontend routes
|
|
81
|
+
- frontend components
|
|
82
|
+
- frontend icons
|
|
83
|
+
- custom form-field or table-cell resources
|
|
84
|
+
- module metadata consumed by backend `ZovaRender.*(...)` references
|
|
85
|
+
|
|
86
|
+
Typical handoff:
|
|
87
|
+
|
|
88
|
+
- generated metadata
|
|
89
|
+
- flavor build output
|
|
90
|
+
- local file dependency sync into Vona
|
|
91
|
+
|
|
92
|
+
Typical consumers:
|
|
93
|
+
|
|
94
|
+
- backend metadata that references frontend resources
|
|
95
|
+
- backend-side tooling and type hints
|
|
96
|
+
- SSR or integration paths that depend on refreshed frontend output
|
|
97
|
+
|
|
98
|
+
## Decision tree
|
|
99
|
+
|
|
100
|
+
Use this decision tree before editing or regenerating anything.
|
|
101
|
+
|
|
102
|
+
### 1. Did backend contract truth change?
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
|
|
106
|
+
- DTO shape changed
|
|
107
|
+
- controller request or response changed
|
|
108
|
+
- validation changed
|
|
109
|
+
- OpenAPI metadata changed
|
|
110
|
+
|
|
111
|
+
Then use the **forward chain**:
|
|
112
|
+
|
|
113
|
+
1. change backend truth first
|
|
114
|
+
2. prove emitted contract output is correct
|
|
115
|
+
3. regenerate frontend consumers
|
|
116
|
+
4. keep frontend follow-up thin
|
|
117
|
+
5. verify consumer alignment
|
|
118
|
+
|
|
119
|
+
See [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk).
|
|
120
|
+
|
|
121
|
+
### 2. Did frontend-owned metadata or resource truth change?
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
|
|
125
|
+
- a custom table cell was added
|
|
126
|
+
- a custom form field was added
|
|
127
|
+
- routes, components, or icons changed
|
|
128
|
+
- backend metadata now references new frontend resources
|
|
129
|
+
|
|
130
|
+
Then use the **reverse chain**:
|
|
131
|
+
|
|
132
|
+
1. change frontend source truth
|
|
133
|
+
2. regenerate metadata when applicable
|
|
134
|
+
3. build the relevant frontend flavor output
|
|
135
|
+
4. run `npm run deps:vona`
|
|
136
|
+
5. verify backend consumers can see the refreshed handoff
|
|
137
|
+
|
|
138
|
+
See [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend).
|
|
139
|
+
|
|
140
|
+
### 3. Do generated artifacts look stale?
|
|
141
|
+
|
|
142
|
+
Examples:
|
|
143
|
+
|
|
144
|
+
- generated SDK still reflects an old endpoint shape
|
|
145
|
+
- generated metadata is missing a new resource
|
|
146
|
+
- rest output did not pick up the latest source change
|
|
147
|
+
|
|
148
|
+
Then diagnose **generated-output drift**:
|
|
149
|
+
|
|
150
|
+
1. confirm the source layer was changed in the right place
|
|
151
|
+
2. confirm the correct generation path was used
|
|
152
|
+
3. regenerate instead of hand-patching
|
|
153
|
+
4. verify the generated output itself before debugging downstream code
|
|
154
|
+
|
|
155
|
+
### 4. Do generated artifacts already look correct, but consumers still behave stale?
|
|
156
|
+
|
|
157
|
+
Examples:
|
|
158
|
+
|
|
159
|
+
- generated `.zova-rest` output already contains the new keys or types
|
|
160
|
+
- generated SDK already contains the new method
|
|
161
|
+
- backend or frontend still behaves as if old local file packages are installed
|
|
162
|
+
|
|
163
|
+
Then suspect **local dependency drift**:
|
|
164
|
+
|
|
165
|
+
1. stop editing source files
|
|
166
|
+
2. prove the generated handoff is already correct
|
|
167
|
+
3. rerun the normal sync flow
|
|
168
|
+
4. only then repair the local install state if consumers still look stale
|
|
169
|
+
|
|
170
|
+
## Forward chain playbook
|
|
171
|
+
|
|
172
|
+
### Stage 1: Backend contract source
|
|
173
|
+
|
|
174
|
+
Author the truth in Vona first.
|
|
175
|
+
|
|
176
|
+
Typical layers:
|
|
177
|
+
|
|
178
|
+
- controllers
|
|
179
|
+
- DTOs
|
|
180
|
+
- entities
|
|
181
|
+
- validation helpers
|
|
182
|
+
- OpenAPI annotations
|
|
183
|
+
|
|
184
|
+
Rule:
|
|
185
|
+
|
|
186
|
+
- do **not** patch generated frontend consumers first when the backend owns truth
|
|
187
|
+
|
|
188
|
+
### Stage 2: Emitted contract proof
|
|
189
|
+
|
|
190
|
+
Before regeneration, verify the backend output is actually correct.
|
|
191
|
+
|
|
192
|
+
Typical checks:
|
|
193
|
+
|
|
194
|
+
- controller contract matches intent
|
|
195
|
+
- DTO and validation align
|
|
196
|
+
- OpenAPI output reflects the intended shape
|
|
197
|
+
|
|
198
|
+
If the emitted contract is wrong, regeneration will only spread the mistake.
|
|
199
|
+
|
|
200
|
+
### Stage 3: Module ownership and generation
|
|
201
|
+
|
|
202
|
+
Regenerate the frontend consumer path deliberately.
|
|
203
|
+
|
|
204
|
+
Typical commands include:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm run zova :openapi:config <module-name>
|
|
208
|
+
npm run zova :openapi:generate <module-name>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
When the target is a module-local SDK, keep ownership constrained with `operations.match` so the module only generates the API surface it actually owns.
|
|
212
|
+
|
|
213
|
+
### Stage 4: Thin frontend follow-up
|
|
214
|
+
|
|
215
|
+
After regeneration, keep frontend follow-up thin.
|
|
216
|
+
|
|
217
|
+
That means:
|
|
218
|
+
|
|
219
|
+
- prefer generated contract consumers over hand-written duplicates
|
|
220
|
+
- use **thin model facades** as semantic wrappers over generated APIs
|
|
221
|
+
- **reuse the existing resource-owner** when the custom API still belongs to an existing resource
|
|
222
|
+
|
|
223
|
+
For resource-bound custom endpoints, prefer `rest-resource.model.resource` as the state owner. A module-local model may still exist, but it should remain a semantic facade instead of becoming a second cache owner.
|
|
224
|
+
|
|
225
|
+
See the downstream pattern in `.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md`.
|
|
226
|
+
|
|
227
|
+
### Stage 5: Consumer verification
|
|
228
|
+
|
|
229
|
+
Verify that generated output and frontend consumers agree.
|
|
230
|
+
|
|
231
|
+
Typical checks:
|
|
232
|
+
|
|
233
|
+
- generated API contains the intended methods
|
|
234
|
+
- model or schema consumers still typecheck
|
|
235
|
+
- UI behavior now matches the regenerated contract
|
|
236
|
+
|
|
237
|
+
## Reverse chain playbook
|
|
238
|
+
|
|
239
|
+
### Stage 1: Frontend-owned source truth
|
|
240
|
+
|
|
241
|
+
Start from the frontend resource or metadata that actually changed.
|
|
242
|
+
|
|
243
|
+
Typical layers:
|
|
244
|
+
|
|
245
|
+
- bean resources
|
|
246
|
+
- components
|
|
247
|
+
- metadata wrappers
|
|
248
|
+
- routes
|
|
249
|
+
- icons
|
|
250
|
+
|
|
251
|
+
Rule:
|
|
252
|
+
|
|
253
|
+
- do **not** treat a frontend-owned resource handoff as frontend-only cleanup if backend consumers depend on it
|
|
254
|
+
|
|
255
|
+
### Stage 2: Generated handoff
|
|
256
|
+
|
|
257
|
+
Refresh the generated metadata or build output that carries the change across the boundary.
|
|
258
|
+
|
|
259
|
+
Typical commands may include:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
npm run zova :tools:metadata <module-name>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
and then the relevant build path for the active edition and flavor.
|
|
266
|
+
|
|
267
|
+
### Stage 3: Vona sync handoff
|
|
268
|
+
|
|
269
|
+
After the frontend-generated handoff is ready, re-sync Vona’s local file dependencies.
|
|
270
|
+
|
|
271
|
+
For the current **Cabloy Basic Admin** branch, the representative sequence is:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
npm run build:zova:admin
|
|
275
|
+
npm run deps:vona
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
If the same resource path must also be available to Web, also refresh the Web branch.
|
|
279
|
+
|
|
280
|
+
For **Cabloy Start**, use the same reverse-chain logic, but resolve the Start-specific flavor names and output paths from the active Start repo before recommending commands.
|
|
281
|
+
|
|
282
|
+
### Stage 4: Consumer verification
|
|
283
|
+
|
|
284
|
+
Verify that backend consumers can now resolve the refreshed frontend-generated handoff.
|
|
285
|
+
|
|
286
|
+
Typical checks:
|
|
287
|
+
|
|
288
|
+
- backend metadata resolves the new frontend resource names
|
|
289
|
+
- generated shared types now appear in backend-side consumers
|
|
290
|
+
- SSR or integration behavior sees the refreshed output
|
|
291
|
+
|
|
292
|
+
## Recovery path for local dependency drift
|
|
293
|
+
|
|
294
|
+
Use this branch only when all of these are already true:
|
|
295
|
+
|
|
296
|
+
- source truth was edited in the right place
|
|
297
|
+
- generation or build output already contains the intended change
|
|
298
|
+
- the normal sync flow already ran
|
|
299
|
+
- consumers still behave stale
|
|
300
|
+
|
|
301
|
+
Then treat the problem as **local dependency drift**.
|
|
302
|
+
|
|
303
|
+
Representative recovery path:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
cd vona && rm -rf node_modules && pnpm install
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
This is a recovery step, not the first response.
|
|
310
|
+
|
|
311
|
+
## Verification by branch
|
|
312
|
+
|
|
313
|
+
### Forward chain
|
|
314
|
+
|
|
315
|
+
- backend source truth is correct
|
|
316
|
+
- emitted OpenAPI or contract output is correct
|
|
317
|
+
- module ownership is constrained
|
|
318
|
+
- generated frontend consumer output is refreshed
|
|
319
|
+
- frontend consumers and UI behavior align
|
|
320
|
+
|
|
321
|
+
### Reverse chain
|
|
322
|
+
|
|
323
|
+
- frontend source truth is correct
|
|
324
|
+
- metadata or build output is refreshed
|
|
325
|
+
- Vona dependency sync completed
|
|
326
|
+
- backend consumers resolve the updated frontend-generated handoff
|
|
327
|
+
|
|
328
|
+
### Local dependency drift
|
|
329
|
+
|
|
330
|
+
- generated artifacts already prove the change exists
|
|
331
|
+
- sync flow already ran
|
|
332
|
+
- reinstall is justified only because consumers still behave stale
|
|
333
|
+
|
|
334
|
+
## Tutorial map
|
|
335
|
+
|
|
336
|
+
Use the tutorial series as examples of the two chains:
|
|
337
|
+
|
|
338
|
+
- [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing) — reverse chain, built-in metadata branch
|
|
339
|
+
- [Tutorial 4: Custom Form/Table Renderers for Level](/fullstack/tutorial-4-custom-level-renderers) — reverse chain, custom resource handoff branch
|
|
340
|
+
- [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing) — forward chain, backend-emitted contract branch
|
|
341
|
+
- [Tutorial 6: One Contract Surface, Four Uses](/fullstack/tutorial-6-one-contract-four-uses) — one field story spanning multiple contract surfaces
|
|
342
|
+
|
|
343
|
+
## Related docs
|
|
344
|
+
|
|
345
|
+
- [Fullstack Introduction](/fullstack/introduction)
|
|
346
|
+
- [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
|
|
347
|
+
- [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
|
|
348
|
+
- [Vona + Zova Integration](/fullstack/vona-zova-integration)
|
|
349
|
+
- [OpenAPI SDK Guide](/frontend/openapi-sdk-guide)
|
|
350
|
+
- [API Schema Guide](/frontend/api-schema-guide)
|
|
@@ -42,17 +42,17 @@ For the current public explanation of this backend capability, see [Cache Guide]
|
|
|
42
42
|
|
|
43
43
|
This is the kind of result Cabloy is designed to support: a framework that stays operationally calm even when the system keeps running for long periods.
|
|
44
44
|
|
|
45
|
-
One internally generated project was kept running continuously for **
|
|
45
|
+
One internally generated project was kept running continuously for **2 days**. At one representative PM2 snapshot, the process looked like this:
|
|
46
46
|
|
|
47
47
|
```text
|
|
48
48
|
┌────┬─────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
|
|
49
49
|
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
|
|
50
50
|
├────┼─────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
|
|
51
|
-
│ 0 │
|
|
51
|
+
│ 0 │ cabloy_*** │ default │ N/A │ cluster │ 226947 │ 2D │ 17 │ online │ 0% │ 376.2mb │ ubuntu │ disabled │
|
|
52
52
|
└────┴─────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
For this
|
|
55
|
+
For this 2-day continuous run, the observed result was **0 memory leak**.
|
|
56
56
|
|
|
57
57
|
The value of this example is not that it is a synthetic micro-benchmark. The value is that it reflects a real long-running project process with a clear, inspectable runtime footprint.
|
|
58
58
|
|