cabloy 5.1.60 → 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.
Files changed (76) 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/references/follow-up-checklist.md +1 -0
  4. package/.claude/skills/cabloy-contract-loop/SKILL.md +89 -16
  5. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
  6. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
  7. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
  8. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +11 -0
  9. package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
  10. package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
  11. package/.claude/skills/cabloy-resource-field-update/SKILL.md +7 -0
  12. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
  13. package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
  14. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
  15. package/CHANGELOG.md +22 -0
  16. package/CLAUDE.md +10 -0
  17. package/cabloy-docs/.vitepress/config.mjs +50 -4
  18. package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
  19. package/cabloy-docs/ai/docs-skills-rules-mapping.md +14 -0
  20. package/cabloy-docs/ai/future-skill-roadmap.md +10 -7
  21. package/cabloy-docs/ai/introduction.md +1 -0
  22. package/cabloy-docs/ai/playbook-backend-module.md +6 -0
  23. package/cabloy-docs/ai/playbook-module-removal.md +164 -0
  24. package/cabloy-docs/ai/skills.md +11 -0
  25. package/cabloy-docs/backend/dto-guide.md +6 -0
  26. package/cabloy-docs/backend/entity-guide.md +18 -0
  27. package/cabloy-docs/backend/introduction.md +2 -0
  28. package/cabloy-docs/backend/serialization-guide.md +10 -0
  29. package/cabloy-docs/backend/status-guide.md +271 -0
  30. package/cabloy-docs/frontend/api-guide.md +2 -0
  31. package/cabloy-docs/frontend/bean-scene-authoring.md +2 -0
  32. package/cabloy-docs/frontend/cli.md +12 -0
  33. package/cabloy-docs/frontend/command-scene-authoring.md +495 -0
  34. package/cabloy-docs/frontend/design-principles.md +6 -0
  35. package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
  36. package/cabloy-docs/frontend/form-guide.md +795 -0
  37. package/cabloy-docs/frontend/foundation.md +29 -0
  38. package/cabloy-docs/frontend/introduction.md +12 -1
  39. package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
  40. package/cabloy-docs/frontend/mock-guide.md +1 -0
  41. package/cabloy-docs/frontend/model-architecture.md +252 -39
  42. package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
  43. package/cabloy-docs/frontend/model-resource-cookbook.md +505 -0
  44. package/cabloy-docs/frontend/model-resource-owner-pattern.md +382 -0
  45. package/cabloy-docs/frontend/model-resource-usage-guide.md +318 -0
  46. package/cabloy-docs/frontend/model-state-guide.md +366 -13
  47. package/cabloy-docs/frontend/openapi-sdk-guide.md +5 -2
  48. package/cabloy-docs/frontend/page-guide.md +6 -0
  49. package/cabloy-docs/frontend/quickstart.md +4 -0
  50. package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
  51. package/cabloy-docs/frontend/server-data.md +2 -0
  52. package/cabloy-docs/frontend/zova-form-source-reading-map.md +295 -0
  53. package/cabloy-docs/frontend/zova-form-under-the-hood.md +556 -0
  54. package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
  55. package/cabloy-docs/frontend/zova-source-reading-map.md +327 -0
  56. package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
  57. package/cabloy-docs/fullstack/contract-loop-playbook.md +350 -0
  58. package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +44 -1
  59. package/cabloy-docs/fullstack/introduction.md +12 -1
  60. package/cabloy-docs/fullstack/openapi-to-sdk.md +19 -9
  61. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +2 -2
  62. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +30 -5
  63. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +9 -7
  64. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +2 -0
  65. package/cabloy-docs/fullstack/tutorials-overview.md +16 -3
  66. package/cabloy-docs/reference/bean-scene-boilerplates.md +2 -0
  67. package/package.json +2 -1
  68. package/scripts/init.ts +2 -18
  69. package/scripts/initTestData.ts +25 -0
  70. package/scripts/upgrade.ts +17 -2
  71. package/vona/pnpm-lock.yaml +94 -4
  72. package/zova/packages-cli/cli/package.json +2 -2
  73. package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
  74. package/zova/packages-cli/cli-set-front/package.json +1 -1
  75. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
  76. package/zova/pnpm-lock.yaml +20 -20
@@ -0,0 +1,271 @@
1
+ # Status Guide
2
+
3
+ This guide explains how Status works in Vona within the Cabloy monorepo.
4
+
5
+ ## Why Status matters
6
+
7
+ Some backend modules need a very small amount of durable module-local state without introducing a full business resource.
8
+
9
+ Typical examples include:
10
+
11
+ - feature toggles owned by one module
12
+ - small structured status payloads
13
+ - module-local runtime flags that should survive process restart
14
+ - lightweight persisted settings that do not justify a dedicated CRUD surface
15
+
16
+ Vona provides Status for exactly that shape.
17
+
18
+ A practical mental model is:
19
+
20
+ - Status is a persisted key/value store
21
+ - keys are scoped by the owning module
22
+ - values are stored as JSON
23
+ - the main public API is a typed `get` / `set` surface
24
+
25
+ ## Create `meta.status`
26
+
27
+ Create a status bean in your module with the shared Vona CLI entrypoint:
28
+
29
+ ```bash
30
+ npm run vona :create:bean meta status -- --module=demo-student
31
+ ```
32
+
33
+ This follows the same `:create:bean` workflow used by other backend bean scenes and metadata beans.
34
+
35
+ The generated shape is representative of:
36
+
37
+ ```typescript
38
+ import { Meta } from 'vona-module-a-meta';
39
+ import { BeanStatusBase } from 'vona-module-a-status';
40
+
41
+ export interface IStatusRecord {}
42
+
43
+ @Meta()
44
+ export class MetaStatus extends BeanStatusBase<IStatusRecord> {}
45
+ ```
46
+
47
+ The important point is that your module defines its own typed status record while reusing the shared persistence and locking behavior from `BeanStatusBase`.
48
+
49
+ ## Define a typed status record
50
+
51
+ Status is most useful when the record shape is explicit.
52
+
53
+ Representative pattern:
54
+
55
+ ```typescript
56
+ interface IStatusUser {
57
+ name: string;
58
+ age: number;
59
+ }
60
+
61
+ export interface IStatusRecord {
62
+ enable: boolean;
63
+ user: IStatusUser;
64
+ }
65
+
66
+ @Meta()
67
+ export class MetaStatus extends BeanStatusBase<IStatusRecord> {}
68
+ ```
69
+
70
+ This gives a practical typed contract:
71
+
72
+ - `get('enable')` returns `boolean | undefined`
73
+ - `set('enable', true)` requires a boolean
74
+ - `get('user')` returns the typed user object or `undefined`
75
+
76
+ So Status is flexible at storage time because the value is JSON, but strongly typed at authoring time because the bean is generic.
77
+
78
+ ## Use `scope.status`
79
+
80
+ After defining `meta.status` in a module, the generated scope exposes it as `scope.status` inside that module.
81
+
82
+ Representative usage:
83
+
84
+ ```typescript
85
+ let value = await this.scope.status.get('enable');
86
+ await this.scope.status.set('enable', true);
87
+ value = await this.scope.status.get('enable');
88
+
89
+ let user = await this.scope.status.get('user');
90
+ await this.scope.status.set('user', { name: 'zhennann', age: 18 });
91
+ user = await this.scope.status.get('user');
92
+ ```
93
+
94
+ A practical behavior summary is:
95
+
96
+ - `get(...)` returns `undefined` when the key has not been written yet
97
+ - `set(...)` creates the key on first write
98
+ - later `set(...)` updates the existing value
99
+
100
+ ## What is actually stored
101
+
102
+ The current source stores Status data in table `aStatus`.
103
+
104
+ The logical identity of a record is:
105
+
106
+ - `module`
107
+ - `name`
108
+
109
+ The stored payload is:
110
+
111
+ - `value` as JSON
112
+
113
+ So a practical storage reading is:
114
+
115
+ | Field | Meaning |
116
+ | -------- | --------------------------------------- |
117
+ | `module` | the owning backend module |
118
+ | `name` | the status key inside that module |
119
+ | `value` | the persisted JSON value for that key |
120
+
121
+ The current migration creates the table with the framework basic fields plus:
122
+
123
+ - `module`
124
+ - `name`
125
+ - `value`
126
+
127
+ This means Status is designed as a small module-scoped persistence surface rather than a general-purpose relational model.
128
+
129
+ ## Module-local scoping
130
+
131
+ One of the most important design points is that Status is scoped by the **consumer module**, not only by the key name.
132
+
133
+ That means two different modules can both use a key such as `enable` without colliding with each other.
134
+
135
+ A practical reading is:
136
+
137
+ - `demo-student + enable` is one status record
138
+ - `demo-course + enable` is a different status record
139
+
140
+ This makes Status a natural fit for module-local state.
141
+
142
+ ## First-write concurrency behavior
143
+
144
+ The current implementation protects first-write creation with Redlock.
145
+
146
+ A practical flow is:
147
+
148
+ 1. attempt to read the current `(module, name)` record
149
+ 2. if the record exists, update it
150
+ 3. if the record does not exist, enter a `lockIsolate(...)` critical section
151
+ 4. re-check the record with a forced fresh read
152
+ 5. insert only if it is still missing
153
+
154
+ This is important in distributed or multi-worker deployments because two workers might otherwise try to create the same logical key at the same time.
155
+
156
+ The design intention is:
157
+
158
+ - ordinary reads stay simple
159
+ - first-write races are serialized
160
+ - the locked re-check avoids stale read behavior during creation
161
+
162
+ For the broader locking model, also see [Redlock Guide](/backend/redlock-guide).
163
+
164
+ ## Relationship to cache and ORM
165
+
166
+ Status is built on top of the Vona ORM model layer.
167
+
168
+ That matters because Status is not a separate storage engine. It participates in the same broader backend persistence model as other ORM-backed data.
169
+
170
+ A practical reading is:
171
+
172
+ - Status persistence is implemented through an ORM model
173
+ - reads can benefit from the framework data-access stack
174
+ - write behavior still follows the framework mutation path
175
+
176
+ For surrounding concepts, also see:
177
+
178
+ - [ORM Guide](/backend/orm-guide)
179
+ - [Cache Guide](/backend/cache-guide)
180
+ - [Migration and Changes](/backend/migration-and-changes)
181
+
182
+ ## Relationship to migration
183
+
184
+ The built-in `a-status` module currently creates its own storage table through `meta.version` with `fileVersion: 1`.
185
+
186
+ For ordinary consumers of Status, the usual workflow is simple:
187
+
188
+ - depend on the shared Status module
189
+ - create your own `meta.status`
190
+ - define your typed record
191
+ - use `scope.status` from your module
192
+
193
+ You do **not** create a separate status table per consuming module.
194
+
195
+ If your own module later outgrows Status and needs a richer schema, that usually means moving to dedicated entity/model resources and managing your own `meta.version` changes directly.
196
+
197
+ ## What Status is good for
198
+
199
+ Status is a strong fit when the data is:
200
+
201
+ - small in size
202
+ - keyed by a fixed or slowly changing set of names
203
+ - naturally owned by one module
204
+ - read or updated by key rather than queried as a collection
205
+
206
+ Typical good fits include:
207
+
208
+ - module enable flags
209
+ - one module-owned progress marker
210
+ - compact structured settings
211
+ - one-off durable state snapshots
212
+
213
+ ## What Status is not for
214
+
215
+ Status is usually the wrong abstraction when you need:
216
+
217
+ - a large collection of rows
218
+ - rich filtering or search
219
+ - relational structure
220
+ - a public CRUD API
221
+ - list, delete, or pagination behavior
222
+ - field-level validation and indexing as a first-class domain concern
223
+
224
+ A practical boundary is:
225
+
226
+ - use Status for a small number of durable module-local keys
227
+ - use entity/model/controller resources when the data becomes a real business resource
228
+
229
+ ## Current implementation notes
230
+
231
+ From the current source, some boundaries are worth knowing:
232
+
233
+ - the public base API is intentionally small: `get` and `set`
234
+ - there is no built-in delete or list convenience API
235
+ - values are stored as JSON
236
+ - first-write concurrency is protected by Redlock
237
+ - the current table creation is lightweight and does not define a separate Status-specific CRUD surface
238
+
239
+ These details make Status easy to use, but they also mean you should not stretch it into a substitute for a richer domain model.
240
+
241
+ ## Recommended workflow
242
+
243
+ A practical Status workflow is:
244
+
245
+ 1. create `meta.status` with the Vona CLI
246
+ 2. define a small typed `IStatusRecord`
247
+ 3. read and write through `this.scope.status`
248
+ 4. keep payloads compact and module-owned
249
+ 5. move to dedicated entity/model resources if the data stops looking like key/value state
250
+
251
+ ## Related guides
252
+
253
+ Read this guide together with:
254
+
255
+ - [Backend CLI](/backend/cli)
256
+ - [Migration and Changes](/backend/migration-and-changes)
257
+ - [ORM Guide](/backend/orm-guide)
258
+ - [Cache Guide](/backend/cache-guide)
259
+ - [Redlock Guide](/backend/redlock-guide)
260
+
261
+ ## Implementation checks for Status changes
262
+
263
+ When adding or revising module-local durable state, ask:
264
+
265
+ 1. is this really a small module-owned key/value need?
266
+ 2. should the state live in `meta.status` instead of a dedicated entity/model resource?
267
+ 3. is the status record shape explicit and typed?
268
+ 4. will the payload remain compact and stable over time?
269
+ 5. do later requirements such as list, delete, filtering, or indexing mean the design should graduate to a richer persistence model?
270
+
271
+ That keeps Status aligned with its intended role in Vona.
@@ -39,6 +39,8 @@ This shows the intended layering clearly:
39
39
  - `$fetch` handles the lower-level request
40
40
  - the API service exposes a business-oriented method such as `retrieveMenus()`
41
41
 
42
+ If the lower-level request path itself needs transport middleware such as headers, JWT handling, mock fallback, SSR short-circuiting, or response normalization, see [Fetch Interceptor Guide](/frontend/fetch-interceptor-guide).
43
+
42
44
  API is also one of the core module-scope resource categories; see [Module Scope](/frontend/module-scope).
43
45
 
44
46
  ## Using the API through module scope
@@ -215,6 +215,8 @@ This is useful when one scene needs multiple scaffold shapes for distinct fronte
215
215
 
216
216
  Representative built-in examples include the `command` scene, which exposes `commandBulk` and `commandRow` variants, and the `tableCell` scene, which exposes a `tableActionRow` variant in module metadata.
217
217
 
218
+ For the built-in command scene’s runtime model, helper bases, metadata flow, and source-reading path, see [Command Scene Authoring](/frontend/command-scene-authoring).
219
+
218
220
  ### `metadataCustom`
219
221
 
220
222
  Use this only when the scene needs additional generated output beyond the standard metadata passes.
@@ -81,6 +81,18 @@ A practical rule is:
81
81
  - a named variant such as `--boilerplate=commandRow` maps to a metadata key such as `boilerplateCommandRow`
82
82
  - supported variants are scene-defined, so do not assume every scene exposes them
83
83
 
84
+ The built-in `command` scene is the clearest current example:
85
+
86
+ ```bash
87
+ npm run zova :create:bean command test -- --module=demo-student
88
+ npm run zova :create:bean command test -- --module=demo-student --boilerplate=commandBulk
89
+ npm run zova :create:bean command test -- --module=demo-student --boilerplate=commandRow
90
+ ```
91
+
92
+ Use the default template for the command shape without the bulk/row helper bases, `commandBulk` for resource-oriented bulk commands, and `commandRow` for row-oriented commands that need both `resource` and `id`.
93
+
94
+ For the command-scene runtime model and source-reading path, see [Command Scene Authoring](/frontend/command-scene-authoring).
95
+
84
96
  For the current cross-stack lookup table, see [Bean Scene Boilerplate Variants](/reference/bean-scene-boilerplates).
85
97
 
86
98
  ## Practical workflow rule