cabloy 5.1.59 → 5.1.60

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 (102) hide show
  1. package/.claude/skills/cabloy-contract-loop/SKILL.md +16 -0
  2. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +26 -0
  3. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +144 -0
  4. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +18 -0
  5. package/.claude/skills/cabloy-resource-field-update/SKILL.md +267 -0
  6. package/.claude/skills/cabloy-resource-field-update/evals/evals.json +53 -0
  7. package/.claude/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +102 -0
  8. package/.claude/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +120 -0
  9. package/.claude/skills/cabloy-resource-field-update/references/follow-up-checklist.md +80 -0
  10. package/.claude/skills/cabloy-resource-field-update/references/verification-checklist.md +97 -0
  11. package/.github/workflows/docs-pages.yml +2 -0
  12. package/.github/workflows/vona-cov-pg.yml +2 -0
  13. package/.github/workflows/vona-test-crud.yml +4 -2
  14. package/.github/workflows/vona-test-mysql.yml +2 -0
  15. package/.github/workflows/vona-test-pg.yml +2 -0
  16. package/.github/workflows/vona-test-sqlite3.yml +2 -0
  17. package/.github/workflows/vona-tsc.yml +2 -0
  18. package/.github/workflows/zova-ui.yml +2 -0
  19. package/.gitignore +0 -4
  20. package/CHANGELOG.md +30 -0
  21. package/CLAUDE.md +2 -0
  22. package/README.md +15 -0
  23. package/cabloy-docs/.vitepress/config.mjs +43 -0
  24. package/cabloy-docs/ai/class-placement-rule.md +2 -0
  25. package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
  26. package/cabloy-docs/ai/future-skill-roadmap.md +17 -2
  27. package/cabloy-docs/backend/bean-scene-authoring.md +350 -0
  28. package/cabloy-docs/backend/cli.md +26 -1
  29. package/cabloy-docs/backend/foundation.md +28 -3
  30. package/cabloy-docs/backend/introduction.md +8 -0
  31. package/cabloy-docs/backend/service-guide.md +2 -0
  32. package/cabloy-docs/backend/websocket-call-flow.md +435 -0
  33. package/cabloy-docs/backend/websocket-guide.md +455 -0
  34. package/cabloy-docs/backend/websocket-protocol-guide.md +381 -0
  35. package/cabloy-docs/backend/websocket-usage-guide.md +356 -0
  36. package/cabloy-docs/frontend/bean-scene-authoring.md +372 -0
  37. package/cabloy-docs/frontend/behavior-guide.md +449 -0
  38. package/cabloy-docs/frontend/cli.md +12 -0
  39. package/cabloy-docs/frontend/introduction.md +5 -0
  40. package/cabloy-docs/frontend/ioc-and-beans.md +10 -9
  41. package/cabloy-docs/frontend/router-tabs-admin-web-comparison.md +206 -0
  42. package/cabloy-docs/frontend/router-tabs-introduction.md +106 -0
  43. package/cabloy-docs/frontend/router-tabs-mechanism.md +469 -0
  44. package/cabloy-docs/frontend/router-tabs-overview.md +227 -0
  45. package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +343 -0
  46. package/cabloy-docs/frontend/ssr-architecture-overview.md +211 -0
  47. package/cabloy-docs/frontend/ssr-build-deploy-guide.md +308 -0
  48. package/cabloy-docs/frontend/ssr-review-checklist.md +184 -0
  49. package/cabloy-docs/frontend/ssr-troubleshooting-guide.md +301 -0
  50. package/cabloy-docs/fullstack/framework-performance.md +3 -3
  51. package/cabloy-docs/fullstack/introduction.md +29 -0
  52. package/cabloy-docs/fullstack/quickstart.md +7 -1
  53. package/cabloy-docs/fullstack/tutorial-1-first-module.md +111 -0
  54. package/cabloy-docs/fullstack/tutorial-2-first-crud.md +122 -0
  55. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +131 -0
  56. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +119 -0
  57. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +144 -0
  58. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +168 -0
  59. package/cabloy-docs/fullstack/tutorials-overview.md +179 -0
  60. package/cabloy-docs/index.md +4 -3
  61. package/cabloy-docs/reference/bean-scene-boilerplates.md +73 -0
  62. package/cabloy-docs/reference/cli-reference.md +2 -0
  63. package/package.json +6 -2
  64. package/scripts/init.ts +18 -2
  65. package/vona/packages-cli/cabloy-cli/package.json +2 -2
  66. package/vona/packages-cli/cli/package.json +1 -1
  67. package/vona/packages-cli/cli-set-api/package.json +1 -1
  68. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.create.module.ts +4 -0
  69. package/vona/packages-vona/vona/package.json +1 -1
  70. package/vona/pnpm-lock.yaml +133 -1088
  71. package/vona/pnpm-workspace.yaml +0 -1
  72. package/vona/src/suite-vendor/a-vona/modules/a-core/assets/static/img/vona.svg +1 -1
  73. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  74. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  75. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -1
  76. package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +2 -2
  77. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  78. package/zova/package.original.json +1 -1
  79. package/zova/packages-cli/cli/package.json +3 -3
  80. package/zova/packages-cli/cli-set-front/cli/templates/init/icon/boilerplate/icons/default/zova.svg +1 -1
  81. package/zova/packages-cli/cli-set-front/package.json +3 -3
  82. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.create.module.ts +4 -0
  83. package/zova/packages-cli/cli-set-front/src/lib/command/create.bean.ts +5 -1
  84. package/zova/packages-utils/zova-vite/package.json +2 -2
  85. package/zova/packages-zova/zova/package.json +2 -2
  86. package/zova/pnpm-lock.yaml +284 -1313
  87. package/zova/pnpm-workspace.yaml +0 -1
  88. package/zova/src/suite/a-home/modules/home-icon/icons/social/cabloy.svg +1 -1
  89. package/zova/src/suite/a-home/modules/home-icon/icons/social/vona.svg +1 -1
  90. package/zova/src/suite/a-home/modules/home-icon/icons/social/zova.svg +1 -1
  91. package/zova/src/suite/a-home/modules/home-icon/src/.metadata/icons/groups/social.svg +3 -3
  92. package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +9 -0
  93. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  94. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +66 -16
  95. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  96. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/package.json +1 -1
  97. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts +60 -18
  98. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableActionRow/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  99. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableCell/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  100. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  101. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  102. package/zova/src/suite-vendor/a-zova/package.json +4 -4
@@ -0,0 +1,131 @@
1
+ # Tutorial 3: Frontend Metadata Sharing
2
+
3
+ <Badge type="info" text="Basic" />
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.
6
+
7
+ You start with the simplest path first: reuse the existing built-in rendering resources for the `level` field.
8
+
9
+ ## Goal
10
+
11
+ By the end of this tutorial, you will understand:
12
+
13
+ - why Cabloy fullstack sharing is bidirectional
14
+ - how a backend field can reuse frontend rendering resources through metadata
15
+ - how one `level` field can participate in schema-driven form and table behavior without a custom component yet
16
+
17
+ ## AI Prompt
18
+
19
+ Give AI a prompt like this:
20
+
21
+ ```text
22
+ Please add a level field to the Student resource. It should be a number field with these enum values:
23
+
24
+ - 1: beginner
25
+ - 2: intermediate
26
+ - 3: advanced
27
+ ```
28
+
29
+ ## Why this step matters
30
+
31
+ This is the right step because it teaches one very specific Cabloy distinction.
32
+
33
+ The goal is not to make backend and frontend share arbitrary component code. The goal is to keep the backend field contract in charge while letting that contract reference frontend render resources through metadata.
34
+
35
+ In other words, this step is about **frontend metadata sharing**: the backend field contract references frontend render resources through metadata.
36
+
37
+ ## CLI commands to inspect/use
38
+
39
+ This tutorial is mainly a contract-refinement step, so the most important habit is inspection before editing.
40
+
41
+ Useful discovery commands from the repo root:
42
+
43
+ ```bash
44
+ npm run vona :
45
+ npm run zova :
46
+ npm run zova :create
47
+ ```
48
+
49
+ You usually do **not** need to generate a custom bean in this tutorial.
50
+
51
+ Instead, inspect the current contract surfaces first:
52
+
53
+ - `vona/src/module/demo-student/src/entity/student.tsx`
54
+ - `vona/src/module/demo-student/src/dto/studentSelectReq.tsx`
55
+
56
+ Usage notes:
57
+
58
+ - keep the backend entity as the main source of truth for the `level` field
59
+ - prefer built-in frontend render resources first
60
+ - delay custom renderer authoring to the next tutorial
61
+
62
+ ## Generated or affected files
63
+
64
+ The key backend contract anchor is:
65
+
66
+ - `vona/src/module/demo-student/src/entity/student.tsx`
67
+
68
+ By the end of this tutorial, the `level` field should follow a built-in path like this:
69
+
70
+ ```typescript
71
+ @Api.field(
72
+ v.title($locale('Level')),
73
+ v.required(),
74
+ ZovaRender.order(3),
75
+ ZovaRender.field('basic-select:formFieldSelect', {
76
+ items: levelItems,
77
+ placeholder: $locale('LevelPlaceholder'),
78
+ }),
79
+ ZovaRender.cell('basic-select:select', { items: levelItems }),
80
+ levelSchema,
81
+ )
82
+ level: number;
83
+ ```
84
+
85
+ A related DTO anchor is:
86
+
87
+ - `vona/src/module/demo-student/src/dto/studentSelectReq.tsx`
88
+
89
+ That DTO already shows how filter-side field metadata can also participate in schema-driven UI.
90
+
91
+ ## What those files mean in the business thread
92
+
93
+ This tutorial teaches one core mental model:
94
+
95
+ - the backend still owns the business field contract
96
+ - the frontend still owns the render resources
97
+ - metadata is the bridge between them
98
+
99
+ Concretely:
100
+
101
+ - `entity/student.tsx` defines `level` as a real business field
102
+ - `levelItems` gives that field a stable set of business options
103
+ - `ZovaRender.field('basic-select:formFieldSelect', ...)` makes the form side schema-aware
104
+ - `ZovaRender.cell('basic-select:select', ...)` makes the table side schema-aware
105
+ - `dto/studentSelectReq.tsx` reminds you that filter-side metadata is also part of the same contract story
106
+
107
+ At this stage, you do not need a custom frontend component to understand the reverse-sharing model.
108
+
109
+ ## Verification
110
+
111
+ 1. make sure the local dev workflow is running:
112
+
113
+ ```bash
114
+ npm run dev
115
+ ```
116
+
117
+ 2. open `http://localhost:7102/admin/`
118
+ 3. enter the **Student** list page from the **Student** menu
119
+ 4. verify that the `level` field appears with select-style behavior in the relevant schema-driven surfaces
120
+ 5. inspect `vona/src/module/demo-student/src/entity/student.tsx` and confirm that the backend field contract now points to built-in frontend render resources instead of page-local hard-coded UI logic
121
+
122
+ ## Read more
123
+
124
+ - [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
125
+ - [API Schema Guide](/frontend/api-schema-guide)
126
+ - [Server Data](/frontend/server-data)
127
+ - [Frontend CLI](/frontend/cli)
128
+
129
+ ## Next step
130
+
131
+ Continue to [Tutorial 4: Custom Form/Table Renderers for Level](/fullstack/tutorial-4-custom-level-renderers).
@@ -0,0 +1,119 @@
1
+ # Tutorial 4: Custom Form/Table Renderers for Level
2
+
3
+ <Badge type="info" text="Basic" />
4
+
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
+
7
+ ## Goal
8
+
9
+ By the end of this tutorial, you will understand:
10
+
11
+ - when built-in render metadata is enough and when a custom renderer is worth adding
12
+ - how a frontend table cell bean and a frontend form-field component can both serve the same backend field
13
+ - how backend metadata points to module-owned frontend render resources
14
+
15
+ ## AI Prompt
16
+
17
+ Give AI a prompt like this:
18
+
19
+ ```text
20
+ Please make the level UI more business-specific in the Student list page and form.
21
+ ```
22
+
23
+ ## Why this step matters
24
+
25
+ This is the right follow-up step because built-in render resources are a good starting point, but some business fields eventually need module-specific behavior.
26
+
27
+ The `level` field is a good teaching example because this step deepens the UI in two concrete ways:
28
+
29
+ - a custom table cell that renders a more business-specific badge style
30
+ - a custom form field that adds helper text, readonly behavior, or module-specific select styling
31
+
32
+ This is where Cabloy’s contract model becomes more practical: the backend field still owns the business contract, while the frontend module progressively deepens the UI behavior behind that contract.
33
+
34
+ ## CLI commands to inspect/use
35
+
36
+ Inspect the Zova create surface first:
37
+
38
+ ```bash
39
+ npm run zova :create
40
+ npm run zova :create:bean --help
41
+ npm run zova :create:component --help
42
+ ```
43
+
44
+ Representative generation commands for this tutorial:
45
+
46
+ ```bash
47
+ npm run zova :create:bean tableCell level -- --module=demo-student
48
+ npm run zova :create:component formFieldLevel -- --module=demo-student
49
+ ```
50
+
51
+ Usage notes:
52
+
53
+ - use `:create:bean` when you need a table-cell render resource under the bean scene
54
+ - use `:create:component` when you need a custom frontend component/controller surface
55
+ - generation gives you the structural starting point, but this tutorial still expects manual refinement so the result matches the `demo-student` teaching implementation
56
+ - after frontend resources exist, return to the backend entity and point `ZovaRender.field(...)` and `ZovaRender.cell(...)` at the custom module resources
57
+
58
+ ## Generated or affected files
59
+
60
+ By the end of this tutorial, your module should provide these teaching anchors:
61
+
62
+ - custom table cell bean:
63
+ - `zova/src/module/demo-student/src/bean/tableCell.level.tsx`
64
+ - custom form-field controller:
65
+ - `zova/src/module/demo-student/src/component/formFieldLevel/controller.tsx`
66
+ - form-field metadata wrapper:
67
+ - `zova/src/module/demo-student/src/.metadata/component/formFieldLevel.ts`
68
+ - backend field contract to update:
69
+ - `vona/src/module/demo-student/src/entity/student.tsx`
70
+
71
+ Representative custom metadata targets are:
72
+
73
+ ```typescript
74
+ ZovaRender.field('demo-student:formFieldLevel', {
75
+ items: levelItems,
76
+ helper: $locale('LevelPlaceholder'),
77
+ })
78
+ ```
79
+
80
+ and:
81
+
82
+ ```typescript
83
+ ZovaRender.cell('demo-student:level', { items: levelItems })
84
+ ```
85
+
86
+ ## What those files mean in the business thread
87
+
88
+ This tutorial makes the split of responsibilities explicit:
89
+
90
+ - `tableCell.level.tsx` owns the custom table-cell rendering behavior for `level`
91
+ - `component/formFieldLevel/controller.tsx` owns the custom form-field behavior for `level`
92
+ - `.metadata/component/formFieldLevel.ts` exposes that component through the module registration surface
93
+ - `entity/student.tsx` remains the backend-owned business contract that chooses which frontend resources should render the field
94
+
95
+ That means the backend still defines the business field, validation, and metadata entry point, while the frontend module owns the implementation details of the richer UI behavior.
96
+
97
+ ## Verification
98
+
99
+ 1. make sure the local dev workflow is running:
100
+
101
+ ```bash
102
+ npm run dev
103
+ ```
104
+
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`
109
+
110
+ ## Read more
111
+
112
+ - [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
113
+ - [Frontend CLI](/frontend/cli)
114
+ - [Component Guide](/frontend/component-guide)
115
+ - [Bean Scene Boilerplate Variants](/reference/bean-scene-boilerplates)
116
+
117
+ ## Next step
118
+
119
+ Continue to [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing).
@@ -0,0 +1,144 @@
1
+ # Tutorial 5: Backend Contract Sharing
2
+
3
+ <Badge type="info" text="Basic" />
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.
6
+
7
+ The teaching thread in this page is the pair of Student actions:
8
+
9
+ - `summary/:id`
10
+ - `deleteForce/:id`
11
+
12
+ ## Goal
13
+
14
+ By the end of this tutorial, you will understand:
15
+
16
+ - how a backend controller and DTO change becomes frontend generated API output
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
19
+
20
+ ## AI Prompt
21
+
22
+ Give AI a prompt like this:
23
+
24
+ ```text
25
+ Please add two custom actions to the Student list:
26
+
27
+ - Summary: return or display a student summary for the selected row
28
+ - 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
+ ```
32
+
33
+ ## Why this step matters
34
+
35
+ This is the right step because it reduces duplicated type work across backend and frontend.
36
+
37
+ Instead of manually synchronizing request and response shapes in two places, this workflow keeps the backend as the source of truth and regenerates the frontend artifacts from that contract.
38
+
39
+ This step also shows that contract sharing is not only about API methods. It also affects how backend row-action metadata becomes frontend table behavior.
40
+
41
+ ## CLI commands to inspect/use
42
+
43
+ Inspect the relevant command surfaces first:
44
+
45
+ ```bash
46
+ npm run zova :openapi
47
+ npm run zova :openapi:config demo-student
48
+ npm run zova :openapi:generate demo-student
49
+ ```
50
+
51
+ If your workflow also needs refreshed rest-contract output for Cabloy Basic, the related build commands are:
52
+
53
+ ```bash
54
+ cd zova && npm run build:rest:cabloyBasicAdmin
55
+ cd zova && npm run build:rest:cabloyBasicWeb
56
+ ```
57
+
58
+ Usage notes:
59
+
60
+ - use the backend controller and DTOs as the starting point
61
+ - inspect the module OpenAPI config before generation
62
+ - prefer regeneration over hand-written duplicate API layers when the module already owns an OpenAPI contract surface
63
+
64
+ ## Generated or affected files
65
+
66
+ The backend contract anchors are:
67
+
68
+ - `vona/src/module/demo-student/src/controller/student.ts`
69
+ - `vona/src/module/demo-student/src/dto/studentSummary.tsx`
70
+ - `vona/src/module/demo-student/src/dto/studentSelectResItem.tsx`
71
+
72
+ By the end of this tutorial, your `demo-student` controller should expose:
73
+
74
+ ```typescript
75
+ @Web.get('summary/:id')
76
+ async summary(...) { ... }
77
+
78
+ @Web.delete('deleteForce/:id')
79
+ async deleteForce(...) { ... }
80
+ ```
81
+
82
+ The frontend contract and consumption anchors are:
83
+
84
+ - OpenAPI config:
85
+ - `zova/src/module/demo-student/cli/openapi.config.ts`
86
+ - generated frontend API:
87
+ - `zova/src/module/demo-student/src/api/demoStudent.ts`
88
+ - frontend model wrapper:
89
+ - `zova/src/module/demo-student/src/model/student.ts`
90
+ - custom row-action cells:
91
+ - `zova/src/module/demo-student/src/bean/tableCell.actionSummary.tsx`
92
+ - `zova/src/module/demo-student/src/bean/tableCell.actionDeleteForce.tsx`
93
+
94
+ After regeneration, `src/api/demoStudent.ts` should contain generated methods such as:
95
+
96
+ - `summary(...)`
97
+ - `deleteForce(...)`
98
+
99
+ ## What those files mean in the business thread
100
+
101
+ This tutorial is easiest to understand as one contract chain:
102
+
103
+ 1. `controller/student.ts` defines the backend action endpoints
104
+ 2. `dto/studentSummary.tsx` defines the response contract for the summary action
105
+ 3. `dto/studentSelectResItem.tsx` defines the row-action metadata that exposes those actions in the Student list page
106
+ 4. `cli/openapi.config.ts` tells the frontend module which backend operations it owns
107
+ 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
110
+
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.
112
+
113
+ ## Verification
114
+
115
+ 1. make sure the local dev workflow is running:
116
+
117
+ ```bash
118
+ npm run dev
119
+ ```
120
+
121
+ 2. open `http://localhost:7102/admin/`
122
+ 3. enter the **Student** list page
123
+ 4. trigger the **Summary** row action and verify that it uses the regenerated frontend API and returns the expected Student summary data
124
+ 5. trigger the **Force Delete** row action and verify that it reaches the custom backend deleteForce contract path
125
+ 6. inspect the source chain and confirm that each layer is present:
126
+ - `controller/student.ts`
127
+ - `dto/studentSummary.tsx`
128
+ - `dto/studentSelectResItem.tsx`
129
+ - `src/api/demoStudent.ts`
130
+ - `src/model/student.ts`
131
+ - `tableCell.actionSummary.tsx`
132
+ - `tableCell.actionDeleteForce.tsx`
133
+
134
+ ## Read more
135
+
136
+ - [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
137
+ - [OpenAPI Guide](/backend/openapi-guide)
138
+ - [OpenAPI SDK Guide](/frontend/openapi-sdk-guide)
139
+ - [SDK Guide](/frontend/sdk-guide)
140
+ - [Server Data](/frontend/server-data)
141
+
142
+ ## Next step
143
+
144
+ Continue to [Tutorial 6: One Contract Surface, Four Uses](/fullstack/tutorial-6-one-contract-four-uses).
@@ -0,0 +1,168 @@
1
+ # Tutorial 6: One Contract Surface, Four Uses
2
+
3
+ <Badge type="info" text="Basic" />
4
+
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
+
7
+ This time the main teaching field is `mobile`, while `level` stays as the supporting example for table and form rendering.
8
+
9
+ ## Goal
10
+
11
+ By the end of this tutorial, you will understand how one business field thread can participate in:
12
+
13
+ 1. validation
14
+ 2. OpenAPI generation
15
+ 3. table and form rendering
16
+ 4. serialization or desensitization
17
+
18
+ ## AI Prompt
19
+
20
+ Give AI a prompt like this:
21
+
22
+ ```text
23
+ Please add a mobile field to the Student resource. It should be required, be at least 11 characters long, and show the middle 4 digits as asterisks in returned data.
24
+ ```
25
+
26
+ ## Why this step matters
27
+
28
+ This is the right capstone step because many frameworks force the same field knowledge to be repeated in many places:
29
+
30
+ - validation rules
31
+ - backend DTOs
32
+ - API documentation
33
+ - frontend forms
34
+ - frontend tables
35
+ - response masking logic
36
+
37
+ Cabloy tries to reduce that duplication through a field-oriented contract and metadata model, and this tutorial lets you inspect that reduction through one concrete field story.
38
+
39
+ ## CLI commands to inspect/use
40
+
41
+ This tutorial is mainly a source-inspection and verification capstone.
42
+
43
+ Useful commands include:
44
+
45
+ ```bash
46
+ npm run zova :openapi:generate demo-student
47
+ npm run dev
48
+ ```
49
+
50
+ Usage notes:
51
+
52
+ - regenerate the frontend contract if your backend field changes affect the generated output
53
+ - treat the backend entity and DTO surfaces as the first place to inspect
54
+ - use the admin UI to confirm both the visible rendering result and the exposed mobile behavior
55
+
56
+ ## Generated or affected files
57
+
58
+ The key backend field contract anchor is:
59
+
60
+ - `vona/src/module/demo-student/src/entity/student.tsx`
61
+
62
+ By the end of this tutorial, the `mobile` field should show the main capstone pattern:
63
+
64
+ ```typescript
65
+ @Api.field(
66
+ v.title($locale('Mobile')),
67
+ v.required(),
68
+ v.min(11),
69
+ studentMobileSerializer(),
70
+ ZovaRender.order(4),
71
+ )
72
+ mobile: string;
73
+ ```
74
+
75
+ The serializer helper lives in:
76
+
77
+ - `vona/src/module/demo-student/src/lib/studentMobile.ts`
78
+
79
+ The summary DTO also participates in the same thread:
80
+
81
+ - `vona/src/module/demo-student/src/dto/studentSummary.tsx`
82
+
83
+ The supporting render example remains:
84
+
85
+ - `vona/src/module/demo-student/src/entity/student.tsx`
86
+ - `ZovaRender.field(...)` for `level`
87
+ - `ZovaRender.cell(...)` for `level`
88
+
89
+ ## What those files mean in the business thread
90
+
91
+ This tutorial works best when you read `mobile` as one continuous contract thread.
92
+
93
+ That is why `mobile` is the main capstone field, while `level` remains the supporting rendering field.
94
+
95
+ ### Use 1: Validation
96
+
97
+ In `entity/student.tsx`, `mobile` already carries validation decisions such as:
98
+
99
+ - `v.required()`
100
+ - `v.min(11)`
101
+
102
+ That means the field definition is part of the request-contract story, not only a persistence concern.
103
+
104
+ ### Use 2: OpenAPI generation
105
+
106
+ The same field contract participates in DTO and controller flows, which then feed machine-readable API output.
107
+
108
+ That is why backend field and DTO changes can later affect what frontend regeneration sees.
109
+
110
+ ### Use 3: Table and form rendering
111
+
112
+ The main rendering example in this series remains `level`, not `mobile`.
113
+
114
+ That is intentional.
115
+
116
+ `level` shows how the same field-oriented contract can carry:
117
+
118
+ - `ZovaRender.field(...)`
119
+ - `ZovaRender.cell(...)`
120
+ - built-in or custom frontend render resources
121
+
122
+ This keeps the “four uses” explanation complete without forcing `mobile` to act like the best rendering example.
123
+
124
+ ### Use 4: Serialization and desensitization
125
+
126
+ The most practical `mobile` lesson is response exposure policy.
127
+
128
+ In `studentMobile.ts`, the helper:
129
+
130
+ - defines the masking pattern
131
+ - returns `v.serializerReplace(...)`
132
+
133
+ That keeps the masking rule close to the field contract ecosystem instead of scattering it into ad hoc controller or service post-processing.
134
+
135
+ ## Verification
136
+
137
+ 1. make sure the local dev workflow is running:
138
+
139
+ ```bash
140
+ npm run dev
141
+ ```
142
+
143
+ 2. open `http://localhost:7102/admin/`
144
+ 3. enter the relevant **Student** page
145
+ 4. verify that `level` still shows the expected render-driven behavior
146
+ 5. verify that `mobile` follows the validation and serialization policy you defined
147
+ 6. inspect these anchors and confirm that the four-use story is concrete rather than abstract:
148
+ - `vona/src/module/demo-student/src/entity/student.tsx`
149
+ - `vona/src/module/demo-student/src/lib/studentMobile.ts`
150
+ - `vona/src/module/demo-student/src/dto/studentSummary.tsx`
151
+
152
+ ## Read more
153
+
154
+ - [Validation Guide](/backend/validation-guide)
155
+ - [OpenAPI Guide](/backend/openapi-guide)
156
+ - [API Schema Guide](/frontend/api-schema-guide)
157
+ - [Server Data](/frontend/server-data)
158
+ - [Serialization Guide](/backend/serialization-guide)
159
+ - [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
160
+ - [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
161
+
162
+ ## Next step
163
+
164
+ After finishing this series, choose the next path based on your current task:
165
+
166
+ - if you want deeper backend contract detail, continue with [Entity Guide](/backend/entity-guide) and [DTO Guide](/backend/dto-guide)
167
+ - if you want deeper frontend contract consumption, continue with [OpenAPI SDK Guide](/frontend/openapi-sdk-guide) and [API Schema Guide](/frontend/api-schema-guide)
168
+ - if you want more CLI-oriented workflow depth, continue with [CLI Reference](/reference/cli-reference)