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
@@ -1,11 +1,13 @@
1
1
  # Frontend Metadata Back to Backend
2
2
 
3
- This page documents the reverse direction of Cabloy’s fullstack collaboration loop: frontend-generated metadata that improves backend-side development and tooling.
3
+ This page is the **reverse chain** deep dive for Cabloy’s bidirectional contract loop: frontend-generated metadata that improves backend-side development and tooling.
4
4
 
5
5
  ## Why this path matters
6
6
 
7
7
  The fullstack collaboration loop in Cabloy is not one-way.
8
8
 
9
+ In the bidirectional [Contract Loop Playbook](/fullstack/contract-loop-playbook), this page covers the **reverse chain**.
10
+
9
11
  For the forward contract-bridge direction from backend OpenAPI to frontend consumption, also see [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk).
10
12
 
11
13
  The backend does not only feed the frontend through OpenAPI. The frontend also generates information that can improve backend-side type hints and integration confidence.
@@ -44,6 +46,8 @@ A practical collaboration loop often looks like this:
44
46
 
45
47
  ## Edition awareness
46
48
 
49
+ The reverse-chain mental model applies to both Cabloy Basic and Cabloy Start.
50
+
47
51
  This path is especially sensitive to edition differences because Basic and Start do not expose the same frontend module and UI shape.
48
52
 
49
53
  So when AI reasons about frontend-generated metadata, it should verify:
@@ -51,6 +55,7 @@ So when AI reasons about frontend-generated metadata, it should verify:
51
55
  - which repo is active
52
56
  - which flavor is active
53
57
  - which generated output belongs to that edition
58
+ - which concrete build and sync commands belong to that edition
54
59
 
55
60
  ## Implementation checks for frontend-metadata changes
56
61
 
@@ -62,3 +67,41 @@ When changing frontend structural resources such as routes or components, ask:
62
67
  4. should the next action be generation and verification rather than only source edits?
63
68
 
64
69
  That keeps the reverse contract loop visible instead of accidental.
70
+
71
+ ## When backend consumes newly added frontend resources
72
+
73
+ This reverse handoff matters most when you create or change frontend resources that backend-side workflows will later consume, such as:
74
+
75
+ - custom form-field renderers
76
+ - custom table-cell renderers
77
+ - other generated frontend metadata that backend `ZovaRender.*(...)` references depend on
78
+
79
+ In that case, do not stop after source edits alone. Use this representative sequence:
80
+
81
+ 1. regenerate frontend metadata when applicable
82
+ 2. build the relevant frontend flavor output so the shared REST/type surface is refreshed
83
+ 3. run `npm run deps:vona` so Vona re-syncs its local file dependencies
84
+ 4. if generated `.zova-rest` output already contains the expected new keys or types but backend-side consumers still look stale, rebuild `vona/node_modules` and reinstall dependencies
85
+
86
+ For the current Cabloy Basic admin flow, the representative commands are:
87
+
88
+ ```bash
89
+ npm run zova :tools:metadata <module-name>
90
+ npm run build:zova:admin
91
+ npm run deps:vona
92
+ ```
93
+
94
+ If the same resource path must also be available for Web, add:
95
+
96
+ ```bash
97
+ npm run build:zova:web
98
+ npm run deps:vona
99
+ ```
100
+
101
+ If Vona still cannot see the refreshed shared types after the normal sync flow, use this recovery path:
102
+
103
+ ```bash
104
+ cd vona && rm -rf node_modules && pnpm install
105
+ ```
106
+
107
+ The key rule is simple: if frontend-generated resources are later consumed by backend tooling or backend metadata, treat the work as a reverse fullstack handoff, not as frontend-only cleanup.
@@ -89,7 +89,18 @@ Cabloy does not treat type sharing as backend-to-frontend only. The collaboratio
89
89
 
90
90
  This two-way contract loop reduces duplicate declarations and lets backend and frontend evolve from generated source truth instead of hand-maintained memory.
91
91
 
92
- For the two directions in more detail, see [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk) and [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend).
92
+ Start with the canonical [Contract Loop Playbook](/fullstack/contract-loop-playbook), then use the directional deep dives [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk) and [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend).
93
+
94
+ Use the playbook to distinguish four cases clearly:
95
+
96
+ - forward chain
97
+ - reverse chain
98
+ - consumer drift
99
+ - local dependency drift
100
+
101
+ The contract-loop model is shared across Cabloy Basic and Cabloy Start. Detect the edition to choose concrete flavor commands and generated-output paths, not to redefine the workflow model.
102
+
103
+ When the reverse direction involves newly added frontend resources that backend tooling or backend metadata will consume, treat that as an operational handoff rather than a conceptual one: refresh generated frontend output, run the relevant flavor build, run `npm run deps:vona`, and if Vona still sees stale shared types, rebuild `vona/node_modules` and reinstall dependencies.
93
104
 
94
105
  ## How the fullstack system stays connected
95
106
 
@@ -1,10 +1,10 @@
1
1
  # Backend OpenAPI to Frontend SDK
2
2
 
3
- This page turns one of Cabloy’s most important fullstack collaboration paths into an explicit guide.
3
+ This page is the **forward chain** deep dive for Cabloy’s bidirectional contract loop.
4
4
 
5
5
  ## Why this path matters
6
6
 
7
- Cabloy’s fullstack productivity depends heavily on a contract loop:
7
+ In the bidirectional [Contract Loop Playbook](/fullstack/contract-loop-playbook), this page covers the **forward chain**:
8
8
 
9
9
  1. Vona emits backend API metadata through Swagger/OpenAPI
10
10
  2. Zova consumes that metadata to generate frontend SDKs and schema-aware helpers
@@ -12,7 +12,7 @@ Cabloy’s fullstack productivity depends heavily on a contract loop:
12
12
 
13
13
  This is one of the strongest AI-leverage paths in the repo because it reduces duplicated type work and keeps backend/frontend coordination closer to source truth.
14
14
 
15
- ## The contract loop in practical terms
15
+ ## The forward chain in practical terms
16
16
 
17
17
  A useful split is:
18
18
 
@@ -20,7 +20,9 @@ A useful split is:
20
20
  - fullstack docs define the bridge from emitted contract to generated SDK
21
21
  - frontend docs define the consumption side of the generated contract
22
22
 
23
- That means this page is the fullstack contract-bridge page, not the backend authoring page and not the frontend usage page.
23
+ That means this page is the forward-chain bridge page, not the backend authoring page and not the frontend usage page.
24
+
25
+ If the changed source is actually a frontend-owned resource that backend consumers later depend on, switch to the reverse-chain guide: [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend).
24
26
 
25
27
  ## Backend side: Vona emits the contract
26
28
 
@@ -70,23 +72,31 @@ cd zova && npm run build:rest:cabloyBasicAdmin
70
72
  cd zova && npm run build:rest:cabloyBasicWeb
71
73
  ```
72
74
 
73
- A practical contract-loop sequence is:
75
+ A practical forward-chain sequence is:
74
76
 
75
77
  1. author or change the backend contract
76
78
  2. emit or inspect backend OpenAPI output
77
- 3. configure frontend module ownership if needed
78
- 4. generate module-level OpenAPI SDK output
79
- 5. run the rest build for the active Basic flavor when needed
80
- 6. consume the generated contract from frontend code instead of re-declaring it manually
79
+ 3. if the frontend generator reads from a local Swagger endpoint, start the backend service first so the endpoint is reachable — in this repo, `npm run dev` is the normal path and exposes Swagger at `http://localhost:7102/swagger/json?version=V31`
80
+ 4. configure frontend module ownership if needed
81
+ 5. generate module-level OpenAPI SDK output
82
+ 6. run the rest build for the active flavor when needed
83
+ 7. consume the generated contract from frontend code instead of re-declaring it manually
84
+ 8. keep frontend follow-up thin by wrapping generated consumers with semantic facades instead of re-declaring the contract
85
+ 9. when the custom API still belongs to an existing resource, reuse the existing resource-owner instead of creating a competing cache owner
81
86
 
82
87
  A practical responsibility split is:
83
88
 
84
89
  - project-level OpenAPI config decides where the backend Swagger/OpenAPI source comes from
85
90
  - module-level OpenAPI config decides which generated contract slice belongs to which frontend module
91
+ - module-level ownership should be declared explicitly with `operations.match` or `operations.ignore`
92
+
93
+ If both `operations.match` and `operations.ignore` are empty, frontend SDK generation should fail fast instead of generating a large unrelated contract surface for the module. That fail-fast behavior helps both developers and AI agents notice the missing ownership boundary immediately and repair the config before the wrong SDK slice is generated.
86
94
 
87
95
  A practical regeneration rule is:
88
96
 
89
97
  - if the backend contract changed, prefer regenerating the SDK/rest layer before hand-editing frontend request code
98
+ - if `npm run zova :openapi:generate ...` fails because the local Swagger source is unavailable, first start the backend service and confirm `http://localhost:7102/swagger/json?version=V31` is reachable before treating generation as broken
99
+ - if the generated consumer path is already correct, but frontend behavior still looks stale, stop patching generated files and diagnose consumer drift or local dependency drift instead
90
100
 
91
101
  ## Cabloy Start workflow
92
102
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  <Badge type="info" text="Basic" />
4
4
 
5
- In this tutorial, one prompt lets AI show the reverse direction of Cabloy’s fullstack contract loop: backend field metadata can reference frontend render resources.
5
+ In this tutorial, one prompt lets AI show the **reverse chain** of Cabloy’s fullstack contract loop: backend field metadata can reference frontend render resources.
6
6
 
7
7
  You start with the simplest path first: reuse the existing built-in rendering resources for the `level` field.
8
8
 
@@ -19,7 +19,7 @@ By the end of this tutorial, you will understand:
19
19
  Give AI a prompt like this:
20
20
 
21
21
  ```text
22
- Please add a level field to the Student resource. It should be a number field with these enum values:
22
+ Please add a level field to the Student resource. It should be a required number field with these enum values:
23
23
 
24
24
  - 1: beginner
25
25
  - 2: intermediate
@@ -4,6 +4,8 @@
4
4
 
5
5
  In this tutorial, one prompt lets AI upgrade the `level` field from built-in render resources to custom frontend renderers owned by the `demo-student` module.
6
6
 
7
+ This is the **reverse chain** custom-resource handoff branch of the contract loop.
8
+
7
9
  ## Goal
8
10
 
9
11
  By the end of this tutorial, you will understand:
@@ -54,6 +56,7 @@ Usage notes:
54
56
  - use `:create:component` when you need a custom frontend component/controller surface
55
57
  - generation gives you the structural starting point, but this tutorial still expects manual refinement so the result matches the `demo-student` teaching implementation
56
58
  - after frontend resources exist, return to the backend entity and point `ZovaRender.field(...)` and `ZovaRender.cell(...)` at the custom module resources
59
+ - once backend metadata starts consuming those new frontend resources, treat the next step as a reverse fullstack handoff rather than frontend-only cleanup: refresh generated output, rebuild the relevant flavor, and re-sync Vona dependencies
57
60
 
58
61
  ## Generated or affected files
59
62
 
@@ -96,22 +99,44 @@ That means the backend still defines the business field, validation, and metadat
96
99
 
97
100
  ## Verification
98
101
 
99
- 1. make sure the local dev workflow is running:
102
+ 1. refresh the generated handoff surfaces before checking backend consumers:
103
+
104
+ ```bash
105
+ npm run zova :tools:metadata demo-student
106
+ npm run build:zova:admin
107
+ npm run deps:vona
108
+ ```
109
+
110
+ If the same renderer path must also be available for Web, also run:
111
+
112
+ ```bash
113
+ npm run build:zova:web
114
+ npm run deps:vona
115
+ ```
116
+
117
+ If backend-side type consumers still cannot see the new shared renderer types even though generated `.zova-rest` output is already correct, rebuild `vona/node_modules` and reinstall dependencies:
118
+
119
+ ```bash
120
+ cd vona && rm -rf node_modules && pnpm install
121
+ ```
122
+
123
+ 2. make sure the local dev workflow is running:
100
124
 
101
125
  ```bash
102
126
  npm run dev
103
127
  ```
104
128
 
105
- 2. open `http://localhost:7102/admin/`
106
- 3. enter the **Student** list page and verify that the `level` column now uses the custom table-cell presentation
107
- 4. open a Student create, update, or view form and verify that the `level` field now uses the custom form-field behavior
108
- 5. inspect `vona/src/module/demo-student/src/entity/student.tsx` and confirm that the backend metadata now points to `demo-student:formFieldLevel` and `demo-student:level`
129
+ 3. open `http://localhost:7102/admin/`
130
+ 4. enter the **Student** list page and verify that the `level` column now uses the custom table-cell presentation
131
+ 5. open a Student create, update, or view form and verify that the `level` field now uses the custom form-field behavior
132
+ 6. inspect `vona/src/module/demo-student/src/entity/student.tsx` and confirm that the backend metadata now points to `demo-student:formFieldLevel` and `demo-student:level`
109
133
 
110
134
  ## Read more
111
135
 
112
136
  - [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
113
137
  - [Frontend CLI](/frontend/cli)
114
138
  - [Component Guide](/frontend/component-guide)
139
+ - [Zova Form Under the Hood](/frontend/zova-form-under-the-hood)
115
140
  - [Bean Scene Boilerplate Variants](/reference/bean-scene-boilerplates)
116
141
 
117
142
  ## Next step
@@ -2,7 +2,7 @@
2
2
 
3
3
  <Badge type="info" text="Basic" />
4
4
 
5
- In this tutorial, one prompt lets AI show the forward direction of Cabloy’s fullstack contract loop: backend API contracts that generate and refresh the frontend consumption surface.
5
+ In this tutorial, one prompt lets AI show the **forward chain** of Cabloy’s fullstack contract loop: backend API contracts that generate and refresh the frontend consumption surface.
6
6
 
7
7
  The teaching thread in this page is the pair of Student actions:
8
8
 
@@ -15,7 +15,8 @@ By the end of this tutorial, you will understand:
15
15
 
16
16
  - how a backend controller and DTO change becomes frontend generated API output
17
17
  - how backend row-action metadata can drive frontend table actions
18
- - how generated API, frontend model helpers, and row-action beans fit into one contract-sharing workflow
18
+ - how generated API, thin frontend model helpers, and row-action beans fit into one forward-chain workflow
19
+ - why custom resource endpoints that still belong to the same resource should reuse the existing resource-owner instead of creating a competing cache owner
19
20
 
20
21
  ## AI Prompt
21
22
 
@@ -26,8 +27,6 @@ Please add two custom actions to the Student list:
26
27
 
27
28
  - Summary: return or display a student summary for the selected row
28
29
  - Force Delete: permanently delete the selected student through a dedicated row action
29
-
30
- Make both actions work end to end, from the backend contract to the Student list page.
31
30
  ```
32
31
 
33
32
  ## Why this step matters
@@ -60,6 +59,8 @@ Usage notes:
60
59
  - use the backend controller and DTOs as the starting point
61
60
  - inspect the module OpenAPI config before generation
62
61
  - prefer regeneration over hand-written duplicate API layers when the module already owns an OpenAPI contract surface
62
+ - keep frontend follow-up thin: treat the module model as a semantic facade over generated API consumers rather than a second contract-definition layer
63
+ - if the custom endpoint still belongs to the existing resource, reuse the existing resource-owner for server-state ownership
63
64
 
64
65
  ## Generated or affected files
65
66
 
@@ -105,10 +106,11 @@ This tutorial is easiest to understand as one contract chain:
105
106
  3. `dto/studentSelectResItem.tsx` defines the row-action metadata that exposes those actions in the Student list page
106
107
  4. `cli/openapi.config.ts` tells the frontend module which backend operations it owns
107
108
  5. `src/api/demoStudent.ts` is the generated typed API surface created from that backend contract
108
- 6. `src/model/student.ts` wraps the generated API in frontend business-facing helper methods
109
- 7. `tableCell.actionSummary.tsx` and `tableCell.actionDeleteForce.tsx` turn those model methods into visible row actions
109
+ 6. `src/model/student.ts` wraps the generated API in a thin frontend semantic facade
110
+ 7. the model should reuse the existing resource-owner for server-state ownership when the new API still belongs to the Student resource
111
+ 8. `tableCell.actionSummary.tsx` and `tableCell.actionDeleteForce.tsx` turn those model methods into visible row actions
110
112
 
111
- That is the practical contract-sharing loop: backend controller and DTO truth flows into generated frontend API output, then into frontend model helpers, and finally into visible table actions.
113
+ That is the practical forward chain: backend controller and DTO truth flows into generated frontend API output, then into thin frontend model helpers, and finally into visible table actions.
112
114
 
113
115
  ## Verification
114
116
 
@@ -4,6 +4,8 @@
4
4
 
5
5
  In this tutorial, one prompt lets AI close the series by showing Cabloy’s core fullstack idea: one field-oriented contract surface can drive several behaviors across backend and frontend.
6
6
 
7
+ This capstone sits on top of both the forward chain and the reverse chain rather than replacing either one.
8
+
7
9
  This time the main teaching field is `mobile`, while `level` stays as the supporting example for table and form rendering.
8
10
 
9
11
  ## Goal
@@ -61,16 +61,29 @@ Those pages explain the repo entrypoints and the CLI-first workflow model that t
61
61
  - [Tutorial 1: Create Your First Module](/fullstack/tutorial-1-first-module)
62
62
  - [Tutorial 2: Create Your First CRUD](/fullstack/tutorial-2-first-crud)
63
63
 
64
- ### Phase 2: Share frontend rendering metadata through the backend contract
64
+ ### Phase 2: Reverse chain — share frontend rendering metadata through the backend contract
65
65
 
66
66
  - [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing)
67
67
  - [Tutorial 4: Custom Form/Table Renderers for Level](/fullstack/tutorial-4-custom-level-renderers)
68
68
 
69
- ### Phase 3: Share backend contracts forward into frontend consumption
69
+ Important handoff note for this phase:
70
+
71
+ - this phase teaches the **reverse chain** of the Cabloy contract loop
72
+ - Tutorial 3 uses the built-in metadata branch
73
+ - Tutorial 4 uses the custom resource handoff branch
74
+ - once a frontend resource created in these tutorials is later consumed by backend metadata, do not stop at frontend source edits alone
75
+ - refresh the generated frontend output, run the relevant flavor build, then run `npm run deps:vona`
76
+ - if backend-side shared types still look stale after that normal sync flow, rebuild `vona/node_modules` and reinstall dependencies
77
+
78
+ See [Contract Loop Playbook](/fullstack/contract-loop-playbook) and [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend) for the full reverse-chain explanation.
79
+
80
+ ### Phase 3: Forward chain — share backend contracts into frontend consumption
70
81
 
71
82
  - [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing)
72
83
 
73
- ### Phase 4: Understand one contract surface through one field story
84
+ This phase teaches the **forward chain** of the contract loop: backend contract truth changes first, generated frontend consumers are refreshed second, and frontend follow-up stays thin and resource-owner-aware.
85
+
86
+ ### Phase 4: One field story across multiple contract surfaces
74
87
 
75
88
  - [Tutorial 6: One Contract Surface, Four Uses](/fullstack/tutorial-6-one-contract-four-uses)
76
89
 
@@ -51,6 +51,8 @@ These backend entries come from the current `vonaModule.onions` metadata in `a-a
51
51
 
52
52
  These frontend entries come from the current `zovaModule.onions` metadata in `a-command` and `a-table`.
53
53
 
54
+ For the built-in command scene’s runtime model and helper-base patterns, see [Command Scene Authoring](/frontend/command-scene-authoring).
55
+
54
56
  ## Guidance for AI-assisted development
55
57
 
56
58
  Do not assume every bean scene supports named variants.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.60",
3
+ "version": "5.1.61",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -22,6 +22,7 @@
22
22
  "type": "module",
23
23
  "scripts": {
24
24
  "init": "node scripts/init.ts",
25
+ "init:test-data": "node scripts/initTestData.ts",
25
26
  "upgrade": "node scripts/upgrade.ts",
26
27
  "upgrade:dry-run": "node scripts/upgrade.ts --dry-run",
27
28
  "vona": "node ./vona/packages-cli/cli/src/bin/vona.ts --projectPath=vona",
package/scripts/init.ts CHANGED
@@ -247,22 +247,7 @@ function buildSsrCabloyBasicStartBatch(): void {
247
247
  }
248
248
  }
249
249
 
250
- // --- Step F: initTestData ---
251
-
252
- function initTestData(): void {
253
- // eslint-disable-next-line
254
- console.log('[init] Initializing test data via npm run test...');
255
- try {
256
- exec('npm run test');
257
- } catch {
258
- // eslint-disable-next-line
259
- console.warn(
260
- '[init] npm run test failed after init completed; Redis may be unavailable, skipping test data initialization',
261
- );
262
- }
263
- }
264
-
265
- // --- Step G: cleanupWorkspaceYaml ---
250
+ // --- Step F: cleanupWorkspaceYaml ---
266
251
 
267
252
  function cleanupWorkspaceYaml(): void {
268
253
  const subProjects = ['vona', 'zova'];
@@ -283,7 +268,7 @@ function cleanupWorkspaceYaml(): void {
283
268
  }
284
269
  }
285
270
 
286
- // --- Step H: init:cabloy-docs ---
271
+ // --- Step G: init:cabloy-docs ---
287
272
 
288
273
  function initCabloyDocs(): void {
289
274
  const pkgPath = resolve(CABLOY_DOCS_DIR, 'package.json');
@@ -306,6 +291,5 @@ initZova();
306
291
  initCabloyDocs();
307
292
  buildSsrCabloyBasicStartBatch();
308
293
  writeVersionMarker();
309
- initTestData();
310
294
  // eslint-disable-next-line
311
295
  console.log('[init] Done!');
@@ -0,0 +1,25 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const ROOT_DIR = resolve(__dirname, '..');
7
+
8
+ function exec(cmd: string): void {
9
+ execSync(cmd, { stdio: 'inherit', cwd: ROOT_DIR });
10
+ }
11
+
12
+ function initTestData(): void {
13
+ // eslint-disable-next-line no-console
14
+ console.log('[init:test-data] Initializing test data via npm run test...');
15
+ try {
16
+ exec('npm run test');
17
+ } catch {
18
+ // eslint-disable-next-line no-console
19
+ console.warn(
20
+ '[init:test-data] npm run test failed after init completed; Redis may be unavailable, skipping test data initialization',
21
+ );
22
+ }
23
+ }
24
+
25
+ initTestData();
@@ -300,7 +300,17 @@ function runInit(dryRun: boolean, version: string): void {
300
300
  exec('npm run init', { CABLOY_VERSION: version } as any);
301
301
  }
302
302
 
303
- // --- Step 5: Cleanup ---
303
+ // --- Step 5: Run init:test-data ---
304
+
305
+ function runInitTestData(dryRun: boolean): void {
306
+ if (dryRun) {
307
+ log(' [dry-run] Run: npm run init:test-data');
308
+ return;
309
+ }
310
+ exec('npm run init:test-data');
311
+ }
312
+
313
+ // --- Step 6: Cleanup ---
304
314
 
305
315
  function cleanup(dryRun?: boolean): void {
306
316
  if (dryRun) {
@@ -366,6 +376,11 @@ async function main(): Promise<void> {
366
376
  runInit(dryRun, latestPackageInfo.version);
367
377
  log('');
368
378
 
379
+ // 5. Run init:test-data
380
+ log('Running npm run init:test-data...');
381
+ runInitTestData(dryRun);
382
+ log('');
383
+
369
384
  if (dryRun) {
370
385
  log(`[dry-run] Current Cabloy version would become: ${latestPackageInfo.version}`);
371
386
  } else {
@@ -374,7 +389,7 @@ async function main(): Promise<void> {
374
389
 
375
390
  log('Upgrade complete!');
376
391
  } finally {
377
- // 5. Cleanup
392
+ // 6. Cleanup
378
393
  cleanup(dryRun);
379
394
  }
380
395
  }
@@ -7403,6 +7403,9 @@ packages:
7403
7403
  zova-module-a-routertabs@5.1.28:
7404
7404
  resolution: {integrity: sha512-GCDEVygoSgND197VBE4uH+rop5zCffWKjWZKboj20X7Wtcen5/stNNL/pNBoSgQmB+vpSnXqsGH2mHd2uq1ddg==}
7405
7405
 
7406
+ zova-module-a-routertabs@5.1.29:
7407
+ resolution: {integrity: sha512-5jiLc2UwWpzFzGbB7zRXH9FTQBcMPCUcF7zvvjZQaUPHlKeiOPKWzf8w3Lf21FOpluFkJ4Hwyz8ApU5tm9/dZw==}
7408
+
7406
7409
  zova-module-a-ssr@5.1.23:
7407
7410
  resolution: {integrity: sha512-KcG1WVyNIkZ6xQ0s1azJQhmbEnEyychsmhsnbAwurpALwmfWFaSGDQlWVAdx2KxSb4TwV+X1iZhHvPnDOxmv5w==}
7408
7411
 
@@ -7418,6 +7421,9 @@ packages:
7418
7421
  zova-module-a-table@5.1.30:
7419
7422
  resolution: {integrity: sha512-/kHtRbI3lcajrjSaY5iYfalMslkYFSb6j4XBLA++pax2M7lCj3xqghRm9YQWDzXyAUNk+e6TxR8o2cREfLXtOQ==}
7420
7423
 
7424
+ zova-module-a-table@5.1.31:
7425
+ resolution: {integrity: sha512-lU3Kx6wPr0VVoPL2YsBEceQ35WenoRGZhyu2rQ0nakslwQ0cjywX4nfevfxUD2AYsQMFqkjYSHBZpZ25337NCA==}
7426
+
7421
7427
  zova-module-a-zod@5.1.27:
7422
7428
  resolution: {integrity: sha512-t5nddb0S78QFJISAbVbMwpUmxejSYQIp4fMlmVs94wT1XXidTUD2e5kwC6sf3HvBn+9io+FBYSKlgqhWxcVOaA==}
7423
7429
 
@@ -7430,9 +7436,15 @@ packages:
7430
7436
  zova-module-a-zova@5.1.69:
7431
7437
  resolution: {integrity: sha512-wRWeERWiHv1VffLSjM+L82jUw4lhN+SykEd2gidAmlzqiJVwr97mqpRfm+4xAa8/i6+lIMbOdgyKnfmREMaC5A==}
7432
7438
 
7439
+ zova-module-a-zova@5.1.70:
7440
+ resolution: {integrity: sha512-FAGLow6iVpMxyLlVoKjeb0xcMQiheOjYVlSUI1m0Q64H8vdMovm5AJRD/79C5ETcHgkVJxgKCVl9C4xN19aTUQ==}
7441
+
7433
7442
  zova-module-rest-resource@5.1.35:
7434
7443
  resolution: {integrity: sha512-bRGoS4WBFj7w74/3Nm2yZzRUu3efUQ4MuOwtRjKHv+Dhl1VFpPE9jwA2o+uHignjmoT1jcZXUb+/OxDT9/FOTQ==}
7435
7444
 
7445
+ zova-module-rest-resource@5.1.36:
7446
+ resolution: {integrity: sha512-lIKtm1ZGbd9uhLglqSXRJDe5el4UVtsOSvE/qrqxib6thtDvu6vFgZMu8ZrrQ8h1KPktZ9WOiX5oD/OpoYG5gg==}
7447
+
7436
7448
  zova-rest-cabloy-basic-admin@file:.zova-rest/cabloy-basic-admin:
7437
7449
  resolution: {directory: .zova-rest/cabloy-basic-admin, type: directory}
7438
7450
 
@@ -7445,12 +7457,18 @@ packages:
7445
7457
  zova-suite-a-zova@5.1.101:
7446
7458
  resolution: {integrity: sha512-150zX7i6ALJgbjhtHquClsvnf9N+zhxwMJeniMXFEFyUfGQ4u5n5nOku41icVl1HzvuFBbHk8sPGNITHAOB9gw==}
7447
7459
 
7460
+ zova-suite-a-zova@5.1.102:
7461
+ resolution: {integrity: sha512-R5HB45pBHN9lZhWRmCuWH0DSMcDb6iBsgCQojxSZNsD8ttSCvWyu2FwNAmCQFguwEuPyZw8ZZndwr/8HAU3IxQ==}
7462
+
7448
7463
  zova-suite-a-zova@5.1.98:
7449
7464
  resolution: {integrity: sha512-sipc11Lc3amHUbvLaluromNELu8XK8fWT2SyK8iTvZuRXMnpTAdE+s0lkfzO3bdmdfBLrlSyJq8z1derDzt67w==}
7450
7465
 
7451
7466
  zova@5.1.102:
7452
7467
  resolution: {integrity: sha512-c1pf2pYQMoB6HqMgIg1hCTwjwI8ZZwi9t1NoyGy/9gz82xBoaE9ykbMnMdn0Ug2vJYfNLCCrH9P1+OF86fWjTg==}
7453
7468
 
7469
+ zova@5.1.103:
7470
+ resolution: {integrity: sha512-AR+Pk9hozKvB6/R/fZ4WPtKX4I0TJxmHx8Ao8dpLovlXhacYi50dUHOTxUQDavwspkWjMDinNqjQWo2MpAVc9g==}
7471
+
7454
7472
  zova@5.1.99:
7455
7473
  resolution: {integrity: sha512-S8voYFvheBH3Qpg2zYRGv3sssqsHCdBROnz/t8E4VmKsWqdhMrMo65p9XR1H1Lk+0J2m2KjA5Zf6dalClnPq3g==}
7456
7474
 
@@ -13064,6 +13082,8 @@ snapshots:
13064
13082
 
13065
13083
  zova-module-a-routertabs@5.1.28: {}
13066
13084
 
13085
+ zova-module-a-routertabs@5.1.29: {}
13086
+
13067
13087
  zova-module-a-ssr@5.1.23:
13068
13088
  dependencies:
13069
13089
  devalue: 5.8.1
@@ -13090,6 +13110,13 @@ snapshots:
13090
13110
  transitivePeerDependencies:
13091
13111
  - vue
13092
13112
 
13113
+ zova-module-a-table@5.1.31(vue@3.5.38(typescript@5.9.3)):
13114
+ dependencies:
13115
+ '@tanstack/table-core': 8.21.3
13116
+ '@tanstack/vue-table': 8.21.3(vue@3.5.38(typescript@5.9.3))
13117
+ transitivePeerDependencies:
13118
+ - vue
13119
+
13093
13120
  zova-module-a-zod@5.1.27:
13094
13121
  dependencies:
13095
13122
  '@cabloy/zod-errors-custom': link:packages-utils/zod-errors-custom
@@ -13136,8 +13163,26 @@ snapshots:
13136
13163
  - typescript
13137
13164
  - vue
13138
13165
 
13166
+ zova-module-a-zova@5.1.70(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)):
13167
+ dependencies:
13168
+ '@cabloy/compose': link:packages-utils/compose
13169
+ '@cabloy/deps': link:packages-utils/deps
13170
+ '@cabloy/json5': link:packages-utils/json5
13171
+ '@cabloy/module-info': 2.0.0
13172
+ '@cabloy/utils': link:packages-utils/utils
13173
+ '@cabloy/vue-router': 4.4.16(vue@3.5.38(typescript@5.9.3))
13174
+ '@cabloy/word-utils': 2.1.14
13175
+ defu: 6.1.7
13176
+ luxon: 3.7.2
13177
+ zova-jsx: 1.1.63(typescript@5.9.3)
13178
+ transitivePeerDependencies:
13179
+ - typescript
13180
+ - vue
13181
+
13139
13182
  zova-module-rest-resource@5.1.35: {}
13140
13183
 
13184
+ zova-module-rest-resource@5.1.36: {}
13185
+
13141
13186
  zova-rest-cabloy-basic-admin@file:.zova-rest/cabloy-basic-admin(typescript@5.9.3):
13142
13187
  dependencies:
13143
13188
  '@tanstack/query-core': 5.101.0
@@ -13146,7 +13191,7 @@ snapshots:
13146
13191
  table-identity: link:packages-utils/table-identity
13147
13192
  vue: 3.5.38(typescript@5.9.3)
13148
13193
  zod: '@cabloy/zod@4.3.6'
13149
- zova: 5.1.102(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))
13194
+ zova: 5.1.103(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))
13150
13195
  zova-jsx: 1.1.63(typescript@5.9.3)
13151
13196
  zova-module-a-api: 5.1.18
13152
13197
  zova-module-a-bean: 5.1.28
@@ -13158,11 +13203,11 @@ snapshots:
13158
13203
  zova-module-a-model: 5.1.27(vue@3.5.38(typescript@5.9.3))
13159
13204
  zova-module-a-openapi: 5.1.34
13160
13205
  zova-module-a-router: 5.1.26
13161
- zova-module-a-routertabs: 5.1.28
13206
+ zova-module-a-routertabs: 5.1.29
13162
13207
  zova-module-a-ssr: 5.1.23
13163
13208
  zova-module-a-style: 5.1.29
13164
- zova-module-a-table: 5.1.30(vue@3.5.38(typescript@5.9.3))
13165
- zova-module-rest-resource: 5.1.35
13209
+ zova-module-a-table: 5.1.31(vue@3.5.38(typescript@5.9.3))
13210
+ zova-module-rest-resource: 5.1.36
13166
13211
  transitivePeerDependencies:
13167
13212
  - '@vue/composition-api'
13168
13213
  - debug
@@ -13266,6 +13311,40 @@ snapshots:
13266
13311
  - typescript
13267
13312
  - vue
13268
13313
 
13314
+ zova-suite-a-zova@5.1.102(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)):
13315
+ dependencies:
13316
+ zova-module-a-api: 5.1.18
13317
+ zova-module-a-app: 5.1.21
13318
+ zova-module-a-bean: 5.1.28
13319
+ zova-module-a-behavior: 5.1.22
13320
+ zova-module-a-behaviors: 5.1.18
13321
+ zova-module-a-boundary: 5.1.18
13322
+ zova-module-a-command: 5.1.29
13323
+ zova-module-a-fetch: 5.1.20
13324
+ zova-module-a-form: 5.1.35(vue@3.5.38(typescript@5.9.3))
13325
+ zova-module-a-icon: 5.1.23
13326
+ zova-module-a-interceptor: 5.1.26
13327
+ zova-module-a-logger: 5.1.23
13328
+ zova-module-a-meta: 5.1.18
13329
+ zova-module-a-model: 5.1.27(vue@3.5.38(typescript@5.9.3))
13330
+ zova-module-a-openapi: 5.1.34
13331
+ zova-module-a-router: 5.1.26
13332
+ zova-module-a-routerstack: 5.1.23
13333
+ zova-module-a-routertabs: 5.1.29
13334
+ zova-module-a-ssr: 5.1.23
13335
+ zova-module-a-ssrhmr: 5.1.19
13336
+ zova-module-a-ssrserver: 5.1.19
13337
+ zova-module-a-style: 5.1.29
13338
+ zova-module-a-table: 5.1.31(vue@3.5.38(typescript@5.9.3))
13339
+ zova-module-a-zod: 5.1.30
13340
+ zova-module-a-zova: 5.1.70(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))
13341
+ transitivePeerDependencies:
13342
+ - '@vue/composition-api'
13343
+ - debug
13344
+ - supports-color
13345
+ - typescript
13346
+ - vue
13347
+
13269
13348
  zova-suite-a-zova@5.1.98(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)):
13270
13349
  dependencies:
13271
13350
  zova-module-a-api: 5.1.18
@@ -13311,6 +13390,17 @@ snapshots:
13311
13390
  - typescript
13312
13391
  - vue
13313
13392
 
13393
+ zova@5.1.103(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)):
13394
+ dependencies:
13395
+ zova-core: 5.1.57(typescript@5.9.3)
13396
+ zova-suite-a-zova: 5.1.102(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))
13397
+ transitivePeerDependencies:
13398
+ - '@vue/composition-api'
13399
+ - debug
13400
+ - supports-color
13401
+ - typescript
13402
+ - vue
13403
+
13314
13404
  zova@5.1.99(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)):
13315
13405
  dependencies:
13316
13406
  zova-core: 5.1.54(typescript@5.9.3)