cabloy 5.1.149 → 5.1.151
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/.cabloy-version +1 -1
- package/.claude/commands/release.md +12 -1
- package/.claude/hooks/contract-loop-gate.ts +35 -17
- package/.claude/skills/cabloy-backend-scaffold/SKILL.md +4 -3
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +3 -2
- package/.claude/skills/cabloy-contract-loop/SKILL.md +4 -3
- package/.claude/skills/cabloy-domain-planning/SKILL.md +4 -3
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +5 -3
- package/.claude/skills/cabloy-master-detail/SKILL.md +4 -3
- package/.claude/skills/cabloy-module-removal/SKILL.md +5 -4
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +8 -5
- package/.claude/skills/cabloy-spec-execution/SKILL.md +169 -0
- package/.claude/skills/cabloy-spec-execution/evals/evals.json +71 -0
- package/.claude/skills/cabloy-spec-execution/references/execution-protocol.md +137 -0
- package/.claude/skills/cabloy-spec-execution/references/status-and-evidence.md +117 -0
- package/.claude/skills/cabloy-spec-generation/SKILL.md +227 -0
- package/.claude/skills/cabloy-spec-generation/evals/evals.json +83 -0
- package/.claude/skills/cabloy-spec-generation/references/repo-aware-discovery.md +101 -0
- package/.claude/skills/cabloy-spec-generation/references/repo-specs-document-set.md +267 -0
- package/.claude/skills/cabloy-spec-generation/references/traceability-and-status-rules.md +135 -0
- package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs +350 -0
- package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.test.mjs +202 -0
- package/.claude/skills/cabloy-workflow/SKILL.md +21 -10
- package/.claude/skills/cabloy-workflow/evals/evals.json +8 -2
- package/.claude/skills/cabloy-workflow/references/edition-detection.md +5 -3
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +4 -3
- package/CHANGELOG.md +41 -0
- package/CLAUDE.md +12 -11
- package/package.json +4 -2
- package/repo-docs/.vitepress/config.mjs +4 -0
- package/repo-docs/ai/docs-skills-rules-mapping.md +6 -6
- package/repo-docs/ai/future-skill-roadmap.md +2 -2
- package/repo-docs/ai/introduction.md +5 -5
- package/repo-docs/ai/playbook-contract-regeneration.md +3 -9
- package/repo-docs/ai/repo-guidance.md +5 -4
- package/repo-docs/ai/rules-and-config.md +2 -2
- package/repo-docs/ai/virtual-decorator-guidance.md +1 -3
- package/repo-docs/backend/cache-guide.md +36 -0
- package/repo-docs/backend/dto-guide.md +7 -6
- package/repo-docs/backend/dto-infer-generation.md +25 -5
- package/repo-docs/backend/introduction.md +1 -1
- package/repo-docs/backend/migration-and-changes.md +27 -2
- package/repo-docs/backend/model-guide.md +1 -1
- package/repo-docs/backend/resource-field-update.md +156 -0
- package/repo-docs/frontend/a-model-under-the-hood.md +38 -0
- package/repo-docs/frontend/a-openapi-under-the-hood.md +13 -2
- package/repo-docs/frontend/form-layout-guide.md +26 -9
- package/repo-docs/frontend/model-resource-best-practices.md +2 -0
- package/repo-docs/frontend/model-resource-cookbook.md +7 -1
- package/repo-docs/frontend/router-tabs-introduction.md +2 -4
- package/repo-docs/frontend/use-state-data-best-practices.md +44 -0
- package/repo-docs/frontend/zova-form-source-reading-map.md +26 -9
- package/repo-docs/frontend/zova-form-under-the-hood.md +11 -0
- package/repo-docs/fullstack/a-pay-payment-suite.md +1 -1
- package/repo-docs/fullstack/contract-loop-playbook.md +4 -0
- package/repo-docs/fullstack/one-to-one-companion-resource-guide.md +2 -2
- package/repo-docs/reference/package-map.md +1 -1
- package/repo-e2e/specs/a-commerce.spec.ts +40 -0
- package/scripts/release.ts +48 -1
- package/scripts/upgrade.ts +18 -7
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/controller/{{resourceName}}.ts_ +2 -2
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/pnpm-lock.yaml +83 -75
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/.metadata/index.ts +108 -108
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +12 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/service/sku.ts +19 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +53 -4
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +148 -148
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAdjust.tsx +37 -3
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +2 -2
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +7 -6
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +1 -1
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +7 -6
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +10 -7
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +4 -4
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +39 -67
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +56 -37
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +5 -5
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +1 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/package.json +6 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/component/tableCellActionAdjustStock.ts +34 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +81 -6
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeStockBalance.ts +32 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +44 -44
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +356 -338
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeStockBalance.ts +17 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/bean/tableCell.actionAdjustStock.tsx +35 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionAdjustStock/controller.tsx +138 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +3 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +3 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/stockBalance.ts +36 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +4 -4
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +8 -8
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +11 -11
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-app/src/bean/behavior.appModal.tsx +2 -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 +2 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/test/model/resource.types.ts +11 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-form/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-form/src/lib/formLayout.ts +58 -9
- package/zova/src/suite-vendor/a-zova/modules/a-form/test/lib/formLayout.test.ts +157 -0
- package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.persister.ts +3 -1
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useQuery.ts +11 -13
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useState.ts +9 -7
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useStateGeneral.ts +5 -12
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/queryPersister.ts +17 -0
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/queryRefetch.ts +34 -0
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/types/query.ts +27 -3
- package/zova/src/suite-vendor/a-zova/modules/a-model/test/lib/queryPersister.test.ts +115 -0
- package/zova/src/suite-vendor/a-zova/modules/a-model/test/lib/queryRefetch.test.ts +84 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/lib/schema.ts +27 -5
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +4 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/schema.ts +2 -5
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/test/lib/schema.test.ts +179 -0
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cabloy-workflow
|
|
3
|
-
description: This skill should be used when the main Cabloy problem is workflow routing before implementation: deciding between Vona backend scaffolding, Zova frontend scaffolding, contract-loop work, or docs/AI-enablement homes such as repo-docs,
|
|
3
|
+
description: This skill should be used when the main Cabloy problem is workflow routing before implementation: deciding between Vona backend scaffolding, Zova frontend scaffolding, contract-loop work, or docs/AI-enablement homes such as repo-docs, an established internal-docs home when present, CLAUDE.md, commands, or skills, including cases where Cabloy Basic vs Cabloy Start assumptions affect that routing. Trigger on requests to route, classify, choose a workflow, choose an edition-specific path, or decide where Cabloy guidance should live. Do not use it once the task is already clearly a backend scaffold, frontend scaffold, or contract-loop job.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cabloy Workflow
|
|
@@ -24,12 +24,21 @@ Check the repository root for these marker files:
|
|
|
24
24
|
|
|
25
25
|
Interpretation:
|
|
26
26
|
|
|
27
|
-
- `__CABLOY_BASIC__` present → this is Cabloy Basic
|
|
28
|
-
- `__CABLOY_START__` present → this is Cabloy Start
|
|
29
|
-
-
|
|
27
|
+
- only `__CABLOY_BASIC__` present → this is Cabloy Basic
|
|
28
|
+
- only `__CABLOY_START__` present → this is Cabloy Start
|
|
29
|
+
- both markers present → treat the repository as ambiguous or invalid and stop before making edition-specific assumptions
|
|
30
|
+
- neither marker present → inspect the owning package scripts and nearby repository structure, then ask before making an edition-specific assumption
|
|
30
31
|
|
|
31
32
|
This matters most for frontend work, UI-layer assumptions, flavor names, suite/module availability, SSR site baselines, project assets, and edition-specific AI guidance.
|
|
32
33
|
|
|
34
|
+
Repository-path availability is independent of edition detection:
|
|
35
|
+
|
|
36
|
+
- inspect a documentation path before recommending or reading it
|
|
37
|
+
- use `repo-docs-internal/` only when an established active-repository home exists
|
|
38
|
+
- treat edition-local internal notes as optional maintainer material, never as a prerequisite for shared workflow routing
|
|
39
|
+
- when an optional path is absent, continue from public docs, bundled skill references, active source, and tests
|
|
40
|
+
- do not create a missing documentation home unless the user explicitly asks to establish one
|
|
41
|
+
|
|
33
42
|
## Step 2: Identify the task layer
|
|
34
43
|
|
|
35
44
|
Classify the request before proposing a workflow.
|
|
@@ -70,7 +79,7 @@ Use the frontend path when the task is about:
|
|
|
70
79
|
Use the docs/AI path when the task is about:
|
|
71
80
|
|
|
72
81
|
- `repo-docs/`
|
|
73
|
-
- `repo-docs-internal/`
|
|
82
|
+
- an established `repo-docs-internal/` home when present
|
|
74
83
|
- `CLAUDE.md`
|
|
75
84
|
- `.claude/commands/`
|
|
76
85
|
- `.claude/skills/`
|
|
@@ -85,7 +94,7 @@ Before inventing a workflow, inspect these shared surfaces:
|
|
|
85
94
|
- `npm run zova`
|
|
86
95
|
- root `CLAUDE.md` if present
|
|
87
96
|
- `repo-docs/` for public guidance
|
|
88
|
-
- `repo-docs-internal/` for maintainer rationale
|
|
97
|
+
- an established `repo-docs-internal/` home for optional maintainer rationale
|
|
89
98
|
|
|
90
99
|
If the request spans backend and frontend, classify it as fullstack by default unless the user clearly wants only one side.
|
|
91
100
|
|
|
@@ -158,15 +167,17 @@ Use `repo-docs/` for:
|
|
|
158
167
|
- reusable AI-facing workflow guidance
|
|
159
168
|
- edition-aware public documentation
|
|
160
169
|
|
|
161
|
-
###
|
|
170
|
+
### Optional internal engineering docs
|
|
162
171
|
|
|
163
|
-
|
|
172
|
+
When an established `repo-docs-internal/` home exists, it may be used for:
|
|
164
173
|
|
|
165
174
|
- ADRs
|
|
166
175
|
- architecture notes
|
|
167
176
|
- maintainer rationale
|
|
168
177
|
- invariants and design boundaries
|
|
169
178
|
|
|
179
|
+
Its absence must not block routing or implementation, and it must not be assumed to exist in every checkout.
|
|
180
|
+
|
|
170
181
|
### Root rules and commands
|
|
171
182
|
|
|
172
183
|
Use `CLAUDE.md` and `.claude/commands/` for:
|
|
@@ -197,7 +208,7 @@ When the request is about whether a backend base class belongs in `src/lib`, `sr
|
|
|
197
208
|
For these requests:
|
|
198
209
|
|
|
199
210
|
- put the durable operational explanation in `repo-docs/`
|
|
200
|
-
- put rationale and invariants
|
|
211
|
+
- when an established internal-docs home exists, put rationale and invariants there; otherwise preserve the public operational explanation and ask before establishing a new maintainer-rationale home
|
|
201
212
|
- keep `CLAUDE.md` short and behavioral
|
|
202
213
|
- do not treat `@Service()` as a business-layer naming decision only; for B2 it is a runtime-anchor placement choice
|
|
203
214
|
|
|
@@ -276,7 +287,7 @@ Verify:
|
|
|
276
287
|
|
|
277
288
|
- referenced paths exist
|
|
278
289
|
- command names still exist
|
|
279
|
-
- public docs, internal
|
|
290
|
+
- public docs, optional internal rationale, and rules tell a consistent story
|
|
280
291
|
- edition-specific notes point to the right repo assumptions
|
|
281
292
|
|
|
282
293
|
### For backend/frontend workflow changes
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"id": 3,
|
|
18
|
-
"prompt": "Please help me decide whether this new AI guidance belongs in public docs,
|
|
19
|
-
"expected_output": "Routes
|
|
18
|
+
"prompt": "Please help me decide whether this new AI guidance belongs in public docs, an internal-docs home when present, CLAUDE.md, or a skill. The guidance is about when to use npm run zova instead of hand-written scaffolding.",
|
|
19
|
+
"expected_output": "Routes shared operational guidance to public docs and Claude rules/skills as appropriate, treats an internal-docs home as optional maintainer material rather than an assumed requirement, and reinforces the CLI-first principle.",
|
|
20
20
|
"files": []
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -48,6 +48,12 @@
|
|
|
48
48
|
"prompt": "I created a linked Cabloy Basic worktree and only need backend tests. What should I do for local environment isolation?",
|
|
49
49
|
"expected_output": "Keeps generic routing read-only and directs the user to the canonical guide plus explicit /cabloy-worktree-environment invocation. It explains that the invoked skill still generates the universal APP_NAME, SERVER_LISTEN_PORT, DEV_SERVER_PORT, DEV_SERVER_HMR_PORT, and derived API_BASE_URL tuple in both broad local files after confirmation; it does not provide a backend-only one-file path.",
|
|
50
50
|
"files": []
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": 9,
|
|
54
|
+
"prompt": "I am in a Cabloy checkout whose active repository currently has no repo-docs-internal directory. I need shared agent guidance and some maintainer rationale. Where should each part go?",
|
|
55
|
+
"expected_output": "Inspects the active repository path rather than making an edition-wide assumption, routes shared operational guidance to existing public docs and Claude rules or skills, and asks which established maintainer-rationale home to use rather than putting rationale into public docs automatically.",
|
|
56
|
+
"files": []
|
|
51
57
|
}
|
|
52
58
|
]
|
|
53
59
|
}
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Primary markers
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Interpret the root markers as exactly one of these states:
|
|
6
6
|
|
|
7
|
-
- `__CABLOY_BASIC__`
|
|
8
|
-
- `__CABLOY_START__`
|
|
7
|
+
- only `__CABLOY_BASIC__` present → Cabloy Basic
|
|
8
|
+
- only `__CABLOY_START__` present → Cabloy Start
|
|
9
|
+
- both markers present → treat the checkout as invalid or ambiguous and stop before making edition-specific assumptions
|
|
10
|
+
- neither marker present → inspect the owning `package.json` and nearby repository structure, then ask before making an edition-specific assumption
|
|
9
11
|
|
|
10
12
|
## Why the markers matter
|
|
11
13
|
|
|
@@ -25,9 +25,10 @@ Check the repository root for these marker files:
|
|
|
25
25
|
|
|
26
26
|
Interpretation:
|
|
27
27
|
|
|
28
|
-
- `__CABLOY_BASIC__` present → this is Cabloy Basic
|
|
29
|
-
- `__CABLOY_START__` present → this is Cabloy Start
|
|
30
|
-
-
|
|
28
|
+
- only `__CABLOY_BASIC__` present → this is Cabloy Basic
|
|
29
|
+
- only `__CABLOY_START__` present → this is Cabloy Start
|
|
30
|
+
- both markers present → treat the repository as ambiguous or invalid and stop before making edition-specific assumptions
|
|
31
|
+
- neither marker present → inspect the owning package scripts and nearby repository structure, then ask before making an edition-specific assumption
|
|
31
32
|
|
|
32
33
|
This matters most when the analysis becomes UI-sensitive, SSR-site-sensitive, flavor-sensitive, or module-set-sensitive.
|
|
33
34
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.151
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add chart specifications and chart support.
|
|
8
|
+
- Add SSR site specifications.
|
|
9
|
+
- Add Cabloy specification execution.
|
|
10
|
+
- Add skill creation support.
|
|
11
|
+
- Add implementation burndown and gantt charts.
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- Fix skill specifications.
|
|
16
|
+
|
|
17
|
+
### Improvements
|
|
18
|
+
|
|
19
|
+
- Refactor skills and skill specification generation.
|
|
20
|
+
- Update dependencies.
|
|
21
|
+
|
|
22
|
+
## 5.1.150
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
- Add `bypassPersister` support.
|
|
27
|
+
- Update query functionality.
|
|
28
|
+
- Add runbook updates.
|
|
29
|
+
- Add schema alias support.
|
|
30
|
+
- Add SKU stock availability support.
|
|
31
|
+
- Update related functionality and resources.
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
- Fix end-to-end tests.
|
|
36
|
+
- Correct `bypassPersister` behavior.
|
|
37
|
+
- Update schema tests.
|
|
38
|
+
|
|
39
|
+
### Improvements
|
|
40
|
+
|
|
41
|
+
- Refactor the student model and service.
|
|
42
|
+
- Improve documentation for `bypassPersister`.
|
|
43
|
+
|
|
3
44
|
## 5.1.149
|
|
4
45
|
|
|
5
46
|
### Features
|
package/CLAUDE.md
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Repository identity
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Detect the active edition from the repository-root marker before making edition-sensitive assumptions:
|
|
6
6
|
|
|
7
|
-
- `__CABLOY_BASIC__`
|
|
7
|
+
- exactly `__CABLOY_BASIC__` present → Cabloy Basic, the public framework/reference edition
|
|
8
|
+
- exactly `__CABLOY_START__` present → Cabloy Start, the private commercial edition delivered as licensed source
|
|
9
|
+
- both markers present → treat the checkout as invalid or ambiguous and stop before giving edition-specific guidance
|
|
10
|
+
- neither marker present → inspect the owning `package.json` and nearby repository structure, then ask before making an edition-specific assumption
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- `__CABLOY_START__`
|
|
12
|
-
|
|
13
|
-
Always detect the active edition before making UI-sensitive assumptions, choosing frontend examples, recommending module-specific workflows, or assuming the project creation path.
|
|
12
|
+
Always perform this detection before making UI-sensitive assumptions, choosing frontend examples, recommending module-specific workflows, or assuming the project creation path.
|
|
14
13
|
|
|
15
14
|
## Monorepo layout
|
|
16
15
|
|
|
@@ -18,7 +17,7 @@ Always detect the active edition before making UI-sensitive assumptions, choosin
|
|
|
18
17
|
- `vona/` contains the backend framework, backend modules, and the Vona CLI.
|
|
19
18
|
- `zova/` contains the frontend framework, frontend modules, and the Zova CLI.
|
|
20
19
|
- `repo-docs/` contains the unified public documentation.
|
|
21
|
-
- `repo-docs-internal
|
|
20
|
+
- `repo-docs-internal/`, when present, contains edition-local maintainer notes and ADRs; treat it as optional supporting material, not as a shared-edition requirement.
|
|
22
21
|
- `repo-specs/` contains product and business specifications, delivery plans, and suite-local ADRs.
|
|
23
22
|
- `repo-e2e/` contains the end-to-end test project.
|
|
24
23
|
- `repo-observability/` contains local observability infrastructure.
|
|
@@ -39,8 +38,9 @@ Before inventing a custom implementation path:
|
|
|
39
38
|
## Documentation boundary
|
|
40
39
|
|
|
41
40
|
- Put user-facing and agent-facing guidance in `repo-docs/`.
|
|
42
|
-
-
|
|
43
|
-
-
|
|
41
|
+
- When an established `repo-docs-internal/` home exists, use it for maintainer rationale, architecture notes, and engineering ADRs. Do not infer or create that path from edition identity alone.
|
|
42
|
+
- If the active repository has no established internal-documentation home, do not block the workflow or move internal rationale into public docs automatically; use existing documentation homes or ask before establishing one.
|
|
43
|
+
- Put product and business specifications, delivery plans, acceptance records, and suite-local ADRs in `repo-specs/` when that repository surface exists.
|
|
44
44
|
- Do not mix internal rationale into public how-to pages unless a trimmed user-facing explanation is genuinely needed.
|
|
45
45
|
|
|
46
46
|
## AI development rules
|
|
@@ -65,6 +65,7 @@ Before inventing a custom implementation path:
|
|
|
65
65
|
- In Zova page routes, any route with dynamic `params` must define `route.name`; do not rely on unnamed path-keyed routes for typed `$params`. Static routes should omit `route.name` unless a documented named-route requirement exists; use `$router.getPagePath(...)` for canonical static URL generation rather than adding a name or alias for convenience. Ordinary business routes without `locale` params should omit app-config aliases unless a documented system, compatibility, or user-facing URL exception requires one. Choose `ssrProfile` from the page's rendering contract: Web remains `public` by default, while `session` is an explicit choice for cookie-backed state, protected admission, personalized first paint, or private SSR data; the absence of a locale parameter alone does not select a profile. `requiresAuth` is independent, so anonymous routes must explicitly use `requiresAuth: false`. Regenerate page metadata after route changes.
|
|
66
66
|
- For frontend async state that affects rendering or interaction across consumers, prefer model-owned `$useStateData(...)` over controller-managed fetch/cache state.
|
|
67
67
|
- Default to establishing such query state during render. Use `disableSuspenseOnInit: true` only for relatively stable query-backed state when you want to skip the init-time `query.suspense()` kick; it does not prevent query creation, fetches, or hydration-time rendering. If strict readiness is needed later, wait explicitly at the interaction boundary.
|
|
68
|
+
- For render-driving async state, read the current query-owned reactive surface (`query.data` or a model-derived projection); an awaited `query.refetch()` result is valid only for one-shot interaction or orchestration and must not become a parallel ongoing controller/render state owner.
|
|
68
69
|
- In SSR, keep server HTML and the client's hydration-time initial render equivalent. When server rendering intentionally omits private, cookie-unavailable, or browser-only state, keep the same neutral shell or placeholder through hydration and defer its query/load/render branch to an explicit post-hydration, admission, mounted, or interaction boundary.
|
|
69
70
|
- Keep repo-wide AI rules in `CLAUDE.md` short and durable; put branching Zova analysis workflows in `.claude/skills/`.
|
|
70
71
|
- Do not modify shared environment identity or ports merely to bypass a busy resource. For intentional parallel worktree setup, follow `repo-docs/fullstack/parallel-worktree-environment.md`; otherwise wait for the shared resource or ask the user. Create or change worktree-local environment overrides only through the explicitly invoked `cabloy-worktree-environment` skill and its confirmation phase, and only in `vona/env/.env.local` and `zova/env/.env.local`; never modify flavor-, mode-, app-mode-, or runtime-specific `.env.*.local` files. The skill derives the standard `APP_NAME`, `SERVER_LISTEN_PORT`, `DEV_SERVER_PORT`, `DEV_SERVER_HMR_PORT`, and API-derived `API_BASE_URL` tuple only from Git worktree metadata and fixed port baselines; never read or expose `.env*` content while recommending values. Admin and Web are alternative commands using this shared tuple and must not run concurrently in one worktree; use another linked worktree for concurrent use. Detect the active edition before choosing scripts, and never run `npm run init` as an automatic follow-up.
|
|
@@ -81,7 +82,7 @@ Before inventing a custom implementation path:
|
|
|
81
82
|
- When adding a persisted field to an existing backend resource, ask the user whether `vonaModule.fileVersion` should be incremented before changing `meta.version.ts` or the module schema path. If yes, add a new migration version and bump `fileVersion`. If no, keep the current `fileVersion` and fold the schema change into the current version path. Do not assume the versioning strategy without confirmation.
|
|
82
83
|
- In shared-database multitenancy, do not use `table.unique(...)` for business uniqueness. Keep ordinary indexes for lookup performance and enforce tenant-scoped uniqueness in the business layer.
|
|
83
84
|
- In Vona, a tenant corresponds to an instance. Ordinary resource-model CRUD is automatically scoped to the active instance; treat records absent from that scope as absent, and do not use raw cross-instance probes merely to choose between `403` and not-found behavior. Model future multi-merchant boundaries explicitly inside an instance.
|
|
84
|
-
- Model cross-Model query-cache dependencies as one directed, acyclic `modelsClear` / `modelsClearedBy` graph, and verify source mutations refresh warmed dependent queries;
|
|
85
|
+
- Model cross-Model query-cache dependencies as one directed, acyclic `modelsClear` / `modelsClearedBy` graph, and verify source mutations refresh warmed dependent queries; follow [Cross-model query-cache dependencies](repo-docs/backend/cache-guide.md#cross-model-query-cache-dependencies) before designing a nontrivial graph.
|
|
85
86
|
- For `@Api.field(...)` and related schemaLike composition, framework guards now preserve previously attached OpenAPI metadata across schema rebuilds, but structure-shaping schemaLike is still order-sensitive. Treat `v.object(...)`, `v.array(...)`, `v.optional()`, `v.nullable()`, `v.default(...)`, and preprocess/transform wrappers as structure-shaping; keep the final structure-defining schemaLike last and verify emitted schema/OpenAPI output after such edits.
|
|
86
87
|
- `@Core.transaction(...)` defaults to `REQUIRED`: it starts a transaction only when none exists and otherwise joins the current datasource transaction without upgrading its isolation. Prefer it over manual `inTransaction` wrappers for atomic service methods; use `REQUIRES_NEW` only when an independently committed boundary is explicitly required.
|
|
87
88
|
- For replay-safe transient failures, use `@Core.retryable(...)` with an explicit `errorCodes` allowlist. It retries the downstream AOP suffix, so place it closest to the method when it must wrap and retry a `@Core.transaction(...)` boundary; use `ownerOnly: true` for dual-role leaves that must not retry inside a caller-owned transaction; do not retry external side effects or infer retryability from isolation level.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cabloy",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.151",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "A Node.js fullstack framework",
|
|
6
6
|
"keywords": [
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"init": "node scripts/init.ts",
|
|
25
25
|
"init:test-data": "node scripts/initTestData.ts",
|
|
26
|
-
"test:scripts": "node --test scripts/initAppName.test.ts",
|
|
27
26
|
"upgrade": "node scripts/upgrade.ts",
|
|
28
27
|
"upgrade:dry-run": "node scripts/upgrade.ts --dry-run",
|
|
29
28
|
"vona": "node ./vona/packages-cli/cli/src/bin/vona.ts --projectPath=vona",
|
|
@@ -57,6 +56,9 @@
|
|
|
57
56
|
"format:fix": "oxfmt --write",
|
|
58
57
|
"lint": "oxlint --disable-nested-config",
|
|
59
58
|
"lint:fix": "oxlint --disable-nested-config --fix",
|
|
59
|
+
"test:spec-charts": "node --test .claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.test.mjs",
|
|
60
|
+
"spec:charts": "node ./.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs",
|
|
61
|
+
"spec:charts:check": "node ./.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs --check",
|
|
60
62
|
"docs:dev": "pnpm --dir repo-docs docs:dev",
|
|
61
63
|
"docs:build": "pnpm --dir repo-docs docs:build",
|
|
62
64
|
"docs:preview": "pnpm --dir repo-docs docs:preview",
|
|
@@ -292,6 +292,10 @@ export default defineConfig({
|
|
|
292
292
|
text: 'Data & CRUD',
|
|
293
293
|
items: [
|
|
294
294
|
{ text: 'CRUD Workflow', link: '/backend/crud-workflow' },
|
|
295
|
+
{
|
|
296
|
+
text: 'Existing Resource Field Update',
|
|
297
|
+
link: '/backend/resource-field-update',
|
|
298
|
+
},
|
|
295
299
|
{ text: 'Migration and Changes', link: '/backend/migration-and-changes' },
|
|
296
300
|
{ text: 'Field Indexes', link: '/backend/field-indexes' },
|
|
297
301
|
{ text: 'ORM Guide', link: '/backend/orm-guide' },
|
|
@@ -38,11 +38,11 @@ Public docs answer questions like:
|
|
|
38
38
|
- how does Zova page or model architecture work?
|
|
39
39
|
- what is different between Cabloy Basic and Cabloy Start?
|
|
40
40
|
|
|
41
|
-
### 2.
|
|
41
|
+
### 2. Optional internal engineering docs
|
|
42
42
|
|
|
43
43
|
Location:
|
|
44
44
|
|
|
45
|
-
-
|
|
45
|
+
- an established internal-documentation home, when the active repository provides one
|
|
46
46
|
|
|
47
47
|
Use internal docs for:
|
|
48
48
|
|
|
@@ -51,7 +51,7 @@ Use internal docs for:
|
|
|
51
51
|
- maintenance boundaries
|
|
52
52
|
- “why this design exists” notes that do not belong in public user docs
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
When available, internal docs answer questions like:
|
|
55
55
|
|
|
56
56
|
- why were docs and internal notes separated?
|
|
57
57
|
- why is AI enablement structured this way?
|
|
@@ -105,7 +105,7 @@ Skills answer questions like:
|
|
|
105
105
|
Use this quick rule:
|
|
106
106
|
|
|
107
107
|
- if people and agents both need to read and understand it, put it in **public docs**
|
|
108
|
-
- if it is maintainer rationale or long-lived design history,
|
|
108
|
+
- if it is maintainer rationale or long-lived design history, use an established internal-documentation home when one exists; otherwise ask before establishing one
|
|
109
109
|
- if it is short repo-wide behavioral guidance, put it in **CLAUDE.md**
|
|
110
110
|
- if it is a named repeatable operator action, put it in a **command**
|
|
111
111
|
- if it is a reusable procedural workflow with branching, put it in a **skill**
|
|
@@ -128,7 +128,7 @@ Use this quick rule:
|
|
|
128
128
|
### Example: “How should a backend base class be placed?”
|
|
129
129
|
|
|
130
130
|
- public operational explanation → [Class Placement Rule](/ai/class-placement-rule)
|
|
131
|
-
- maintainer rationale and invariants →
|
|
131
|
+
- maintainer rationale and invariants → an established internal-documentation home, when available
|
|
132
132
|
- default repo-wide behavior → `CLAUDE.md`
|
|
133
133
|
- procedural decision workflow → `cabloy-workflow` skill
|
|
134
134
|
|
|
@@ -153,7 +153,7 @@ Use this quick rule:
|
|
|
153
153
|
### Example: “How should AI remove an existing module cleanly?”
|
|
154
154
|
|
|
155
155
|
- public operational explanation → [Playbook: Module Removal](/ai/playbook-module-removal)
|
|
156
|
-
- maintainer rationale and pitfalls →
|
|
156
|
+
- maintainer rationale and pitfalls → an established internal-documentation home, when available
|
|
157
157
|
- avoid putting the full workflow in `CLAUDE.md` because the task needs branching, cleanup order, generated-runtime recovery, and verification
|
|
158
158
|
- procedural decision workflow → `cabloy-module-removal` skill
|
|
159
159
|
|
|
@@ -85,7 +85,7 @@ Primary dependencies:
|
|
|
85
85
|
|
|
86
86
|
- Vona entity / migration / DTO workflow knowledge
|
|
87
87
|
- Zova metadata/build flows when renderer follow-up is involved
|
|
88
|
-
-
|
|
88
|
+
- [Existing Resource Field Update](/backend/resource-field-update)
|
|
89
89
|
|
|
90
90
|
### 5. Metadata refresh skill
|
|
91
91
|
|
|
@@ -148,7 +148,7 @@ The purpose is to create a small number of high-leverage skills that directly re
|
|
|
148
148
|
|
|
149
149
|
- `repo-docs/`
|
|
150
150
|
- `CLAUDE.md`
|
|
151
|
-
-
|
|
151
|
+
- an established internal-documentation home, when present
|
|
152
152
|
- `.claude/skills/`
|
|
153
153
|
- the Vona and Zova CLIs
|
|
154
154
|
|
|
@@ -8,7 +8,7 @@ The Cabloy monorepo is a good fit for AI vibe coding because the source tree alr
|
|
|
8
8
|
- Vona CLI source and command groups
|
|
9
9
|
- Zova CLI source and command groups
|
|
10
10
|
- archived docs that still capture valuable concepts
|
|
11
|
-
- internal engineering docs for maintainers
|
|
11
|
+
- optional internal engineering docs for maintainers when the active repository provides them
|
|
12
12
|
- Claude commands and skills
|
|
13
13
|
|
|
14
14
|
## The main design goal
|
|
@@ -20,7 +20,7 @@ The goal is to make AI **reuse the repo’s existing conventions directly**, esp
|
|
|
20
20
|
- CLI commands
|
|
21
21
|
- root scripts
|
|
22
22
|
- repo markers
|
|
23
|
-
- internal architecture notes
|
|
23
|
+
- optional internal architecture notes when the active repository provides them
|
|
24
24
|
- shared public documentation
|
|
25
25
|
|
|
26
26
|
## How to approach AI work
|
|
@@ -29,7 +29,7 @@ For contributor and automation workflows in this repository, prefer this order:
|
|
|
29
29
|
|
|
30
30
|
1. inspect the active edition and repo markers before making UI-sensitive or workflow-sensitive assumptions
|
|
31
31
|
2. inspect root scripts, Vona CLI, and Zova CLI before inventing manual scaffolding or custom workflow steps
|
|
32
|
-
3. use public docs for durable user-facing guidance
|
|
32
|
+
3. use public docs for durable user-facing and agent-facing guidance; consult an established internal-documentation home only when the active repository provides one for maintainer rationale
|
|
33
33
|
4. encode repeatable behavior in Claude rules, commands, or skills instead of relying on unstated habits
|
|
34
34
|
|
|
35
35
|
## The knowledge layers
|
|
@@ -40,9 +40,9 @@ Use `repo-docs/` for user-facing and agent-facing guidance that should remain du
|
|
|
40
40
|
|
|
41
41
|
For normal project usage, prefer the user-facing entry docs such as [Fullstack Quickstart](/fullstack/quickstart). This AI section focuses on repository workflows and AI vibe coding.
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### Optional internal engineering docs
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
When an established internal-documentation home exists, use it for architecture notes, ADRs, and maintainer rationale that should not be mixed into public how-to documentation. Its absence must not block a shared workflow or cause internal rationale to be moved into public how-to documentation automatically.
|
|
46
46
|
|
|
47
47
|
### Claude rules and commands
|
|
48
48
|
|
|
@@ -52,17 +52,11 @@ Before regenerating frontend artifacts:
|
|
|
52
52
|
|
|
53
53
|
## Step 4: Regenerate the frontend-side contract artifacts
|
|
54
54
|
|
|
55
|
-
Use the Zova OpenAPI and REST-generation path rather than manually updating request code first.
|
|
55
|
+
Use the Zova OpenAPI and REST-generation path rather than manually updating request code first. Follow the canonical [Contract Loop Playbook](/fullstack/contract-loop-playbook#forward-chain-playbook) for the active edition’s complete generation and verification sequence.
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
Do not treat `build:rest:*` as a standalone current command recipe. Resolve the active edition’s full build path from the canonical playbook and current root scripts so SSR bundle and REST output stay synchronized.
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
npm run zova :openapi:generate ...
|
|
61
|
-
cd zova && npm run build:rest:cabloyBasicAdmin
|
|
62
|
-
cd zova && npm run build:rest:cabloyBasicWeb
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
For Start, use the Start-specific flavor paths from that repo.
|
|
59
|
+
For Start, resolve Start-specific flavor paths from that repository.
|
|
66
60
|
|
|
67
61
|
## Step 5: Inspect affected frontend layers
|
|
68
62
|
|
|
@@ -8,10 +8,10 @@ Check the root repository signals first:
|
|
|
8
8
|
|
|
9
9
|
- `package.json`
|
|
10
10
|
- edition marker files such as `__CABLOY_BASIC__` or `__CABLOY_START__`
|
|
11
|
-
-
|
|
11
|
+
- an established internal-documentation home, when present
|
|
12
12
|
- root `.claude/` assets
|
|
13
13
|
|
|
14
|
-
These
|
|
14
|
+
These surfaces tell the agent which repo it is in and which scripts are canonical. Inspect an internal-documentation home only when the active repository actually provides one.
|
|
15
15
|
|
|
16
16
|
## 2. Prefer framework entrypoints over scattered examples
|
|
17
17
|
|
|
@@ -27,10 +27,11 @@ For frontend workflows:
|
|
|
27
27
|
|
|
28
28
|
This is more reliable than copying old file structures from examples without understanding the command surface that created them.
|
|
29
29
|
|
|
30
|
-
## 3. Use docs and internal notes for different purposes
|
|
30
|
+
## 3. Use public docs and optional internal notes for different purposes
|
|
31
31
|
|
|
32
32
|
- use `repo-docs/` to explain how people and agents should work
|
|
33
|
-
-
|
|
33
|
+
- when an established internal-documentation home exists, use it for maintainer rationale
|
|
34
|
+
- when it does not exist, continue from public docs, rules, skills, source, and tests; do not create a new documentation home implicitly
|
|
34
35
|
|
|
35
36
|
## 4. Treat edition detection as mandatory for UI-sensitive work
|
|
36
37
|
|
|
@@ -8,7 +8,7 @@ Use the root `CLAUDE.md` for concise, durable operational guidance such as:
|
|
|
8
8
|
|
|
9
9
|
- how the monorepo is organized
|
|
10
10
|
- where public docs live
|
|
11
|
-
-
|
|
11
|
+
- whether an established internal-documentation home is available
|
|
12
12
|
- which command entrypoints are preferred
|
|
13
13
|
- why edition detection is mandatory before UI-sensitive guidance or project-creation assumptions
|
|
14
14
|
|
|
@@ -26,4 +26,4 @@ Use Claude settings for permissions and execution environment, not as the primar
|
|
|
26
26
|
|
|
27
27
|
## Documentation boundary
|
|
28
28
|
|
|
29
|
-
If a rule is important for people and agents to understand, it probably belongs in public docs too.
|
|
29
|
+
If a rule is important for people and agents to understand, it probably belongs in public docs too. When an established internal-documentation home exists, it may hold maintainer rationale rather than user-facing workflow. Do not infer or create such a home from edition identity alone.
|
|
@@ -201,6 +201,4 @@ Read these pages together:
|
|
|
201
201
|
- [Global Bean Lookup](/ai/global-bean-lookup)
|
|
202
202
|
- [Docs, Skills, Rules, and CLI Mapping](/ai/docs-skills-rules-mapping)
|
|
203
203
|
|
|
204
|
-
For maintainer-level rationale,
|
|
205
|
-
|
|
206
|
-
- `repo-docs-internal/architecture/virtual-decorator-runtime-semantics.md`
|
|
204
|
+
For maintainer-level rationale, consult an established internal-documentation home when the active repository provides one. The public guidance above is the complete shared operational rule.
|
|
@@ -52,6 +52,42 @@ Representative areas include:
|
|
|
52
52
|
- related-model cache clearing
|
|
53
53
|
- custom cache-clearing logic
|
|
54
54
|
|
|
55
|
+
## Cross-model query-cache dependencies
|
|
56
|
+
|
|
57
|
+
When a mutation in one Model changes the members, totals, projections, includes, or visibility of a query cached by another Model, declare an explicit cross-model dependency. Decide this from **query-result semantics**, not merely from a relation or foreign key.
|
|
58
|
+
|
|
59
|
+
### Choose one directed declaration
|
|
60
|
+
|
|
61
|
+
Express each dependency as one source-to-target edge:
|
|
62
|
+
|
|
63
|
+
- `modelsClear` declares targets from the source Model;
|
|
64
|
+
- `modelsClearedBy` declares sources from the target Model.
|
|
65
|
+
|
|
66
|
+
They normalize to the same direction. Choose the form that makes local ownership clearest, but never declare both forms for the same edge.
|
|
67
|
+
|
|
68
|
+
### Keep the graph acyclic
|
|
69
|
+
|
|
70
|
+
Keep the dependency graph directed, acyclic, and free of duplicate edges. A normal target clear can propagate transitively to its own dependent query caches, so reverse or duplicate declarations are not a way to increase reliability.
|
|
71
|
+
|
|
72
|
+
The default behavior clears affected **query caches**. It does not make a cross-Model entity cache relationship, replace a lock, enforce uniqueness, or create a transaction boundary.
|
|
73
|
+
|
|
74
|
+
### Use custom clearing deliberately
|
|
75
|
+
|
|
76
|
+
`modelsClearedByFn` replaces the normal target-clear behavior for that dependency. When using it, explicitly own the target clear and any required downstream propagation. Do not add it as if it were an additional callback around the normal path.
|
|
77
|
+
|
|
78
|
+
Prefer normal Model or service mutation paths so source invalidation, transaction-aware re-clearing, and configured cache behavior remain active.
|
|
79
|
+
|
|
80
|
+
### Verify a warmed dependent query
|
|
81
|
+
|
|
82
|
+
For every new dependency path, add a regression test that:
|
|
83
|
+
|
|
84
|
+
1. warms the dependent Model query;
|
|
85
|
+
2. mutates the source through the normal Model or service path;
|
|
86
|
+
3. repeats the dependent query;
|
|
87
|
+
4. proves that the result now reflects the mutation.
|
|
88
|
+
|
|
89
|
+
This test demonstrates business invalidation rather than relying on test-runner scheduling or cache implementation assumptions.
|
|
90
|
+
|
|
55
91
|
## Consistency strategy
|
|
56
92
|
|
|
57
93
|
Vona also clears or compensates cache automatically when model mutation occurs.
|
|
@@ -183,7 +183,7 @@ A practical split is:
|
|
|
183
183
|
- use inferred DTOs when the contract closely follows model structure or query shape
|
|
184
184
|
- wrap inferred DTOs in a named DTO class when reuse or discoverability becomes more important
|
|
185
185
|
|
|
186
|
-
When stable Entity, Model, relation, or query truth already exists, prefer inference first: use `$Dto.*` with `columns`, `include`, or `dtoClass` to define the projection; use `@Dto({ fields })` with `$makeMetadata(...)` for metadata-only differences or `$makeSchema(...)` for schema and validation differences;
|
|
186
|
+
When stable Entity, Model, relation, or query truth already exists, prefer inference first: use `$Dto.*` with `columns`, `include`, or `dtoClass` to define the projection; use `@Dto({ fields })` with `$makeMetadata(...)` only for metadata-only differences on an existing inferred/projected field, or `$makeSchema(...)` for schema and validation differences. A true virtual `fields` key absent from that projection must use `$makeSchema(...)` with a final concrete `z.<type>()` schema; `fieldSource(...)` maps its binding but supplies no type. Add an `@Api.field(...)` member only for a genuinely new declared DTO property. See [Virtual fields in the DTO fields map](/backend/dto-infer-generation#virtual-fields-in-the-dto-fields-map) for the full decision rule. Keep an explicit DTO as a deliberate fallback when no suitable upstream truth exists or the inferred composition is less clear.
|
|
187
187
|
|
|
188
188
|
Advanced inferred DTO shaping can also stay named and reusable through helper options such as `dtoClass`, especially for relation-aware contracts and nested DTO surfaces. `$Dto.get(...)` otherwise keeps the complete model-aware read shape by default; use `columns` or `dtoClass` for a genuine business projection, not merely to remove `iid` or `deleted`. For the canonical authoring sequence, see [Default-first three-layer DTO authoring](/backend/dto-infer-generation#default-first-three-layer-dto-authoring) and [Default read shape versus a public projection](/backend/dto-infer-generation#default-read-shape-versus-a-public-projection).
|
|
189
189
|
|
|
@@ -205,11 +205,12 @@ When creating DTOs:
|
|
|
205
205
|
|
|
206
206
|
1. check whether an Entity, Model, relation, or query shape already provides suitable upstream contract truth
|
|
207
207
|
2. define the inferred projection before redeclaring fields: choose the `$Dto.*` helper and, where needed, `columns`, `include`, or `dtoClass`
|
|
208
|
-
3. use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement of an inferred field
|
|
209
|
-
4.
|
|
210
|
-
5.
|
|
211
|
-
6.
|
|
212
|
-
7.
|
|
208
|
+
3. use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement of an inferred/projected field
|
|
209
|
+
4. for a true virtual key added only through `@Dto({ fields })`, use `$makeSchema(...)` with a final concrete `z.<type>()` schema; `fieldSource(...)` supplies no missing type
|
|
210
|
+
5. use `@Api.field(...)` for a genuinely new declared DTO property, not as a second declaration of an inferred field
|
|
211
|
+
6. keep DTO validation and OpenAPI concerns aligned, and keep the final structure-defining schema last when using schema-like composition
|
|
212
|
+
7. decide whether the contract should remain inferred, be wrapped in a named inferred DTO, or deliberately fall back to an explicit DTO
|
|
213
|
+
8. treat DTO design as part of the contract between backend handlers, models, and frontend integration
|
|
213
214
|
|
|
214
215
|
## Where to read next
|
|
215
216
|
|
|
@@ -193,6 +193,25 @@ export class DtoStudentSelectReq extends $Dto.queryPage(EntityStudent, [
|
|
|
193
193
|
|
|
194
194
|
Framework DTO composition preserves inherited OpenAPI metadata when a field schema is refined. That includes metadata such as titles, render information, and scene identity. It does **not** make structure-shaping schema-like arguments order-independent: keep the final structure-defining argument last and verify the effective schema rather than assuming a metadata merge can repair a reordered schema.
|
|
195
195
|
|
|
196
|
+
#### Virtual fields in the DTO fields map
|
|
197
|
+
|
|
198
|
+
The Layer 2 `$makeMetadata(...)` rule has a precondition: the field key must already be supplied by the inferred projection, whether through the `$Dto.*` base, `columns`, `include`, or `dtoClass`. It overlays metadata on that existing runtime schema.
|
|
199
|
+
|
|
200
|
+
A **true virtual DTO field** is a key added only through `@Dto({ fields })` and absent from that inherited projection. Define such a key with `$makeSchema(...)` and a final concrete Zod schema, even when its purpose is only to map a renderer to a nested source:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const descriptionMarkdownField = $makeSchema(
|
|
204
|
+
ZovaRender.fieldSource('content.descriptionMarkdown'),
|
|
205
|
+
ZovaRender.field('basic-markdown:formFieldMarkdown'),
|
|
206
|
+
v.optional(),
|
|
207
|
+
z.string(),
|
|
208
|
+
);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`z.string()` establishes the virtual key's validation and emitted OpenAPI type. `fieldSource(...)` only maps the DTO-facing key to the canonical source path used by downstream schema-driven UI; it does not supply a type. `$makeMetadata(...)` alone has no inherited schema to overlay for a true virtual key, so its metadata is attached to an unconstrained fallback rather than a meaningful field schema.
|
|
212
|
+
|
|
213
|
+
Use a class-body `@Api.field(...)` member instead when the new field should be a declared, statically typed DTO property rather than a contract-only `fields`-map key.
|
|
214
|
+
|
|
196
215
|
`@Dto({ fields })` changes the runtime contract and metadata. It does not rewrite the TypeScript property type inferred from the `$Dto.*` base class. Do not add a duplicate `declare` field or a second field decorator solely to mirror a runtime schema restriction unless a separate static contract is genuinely required and is type-compatible with the inferred base.
|
|
197
216
|
|
|
198
217
|
### Layer 3: add contract-only fields
|
|
@@ -507,10 +526,11 @@ When evaluating a return shape or input contract that closely follows model stru
|
|
|
507
526
|
2. is the contract get/list/query/create/update/aggregate/group oriented, and which `$Dto.*` helper matches it?
|
|
508
527
|
3. should `columns`, `include`, `with`, or `dtoClass` define the projection boundary?
|
|
509
528
|
4. should the inferred DTO stay inline or be wrapped in a named DTO class?
|
|
510
|
-
5. for every local difference, is it
|
|
511
|
-
6.
|
|
512
|
-
7.
|
|
513
|
-
8.
|
|
514
|
-
9.
|
|
529
|
+
5. for every local difference, does the `fields` key already have an inferred/projected schema, or is it a true virtual key?
|
|
530
|
+
6. use `$makeMetadata(...)` only for metadata-only refinement of an inferred/projected field; define every true virtual key with `$makeSchema(...)` and a final concrete `z.<type>()` schema
|
|
531
|
+
7. is every `@Api.field(...)` member genuinely new instead of a redeclared inferred field?
|
|
532
|
+
8. if `$makeSchema(...)` is used, is the structure-defining schema last and is emitted schema/OpenAPI verification planned?
|
|
533
|
+
9. does the resulting DTO also affect OpenAPI and frontend generation paths?
|
|
534
|
+
10. is CRUD generation already giving enough contract structure that another handwritten DTO would be redundant, or is an explicit DTO clearer?
|
|
515
535
|
|
|
516
536
|
That helps reduce redundant type work and keeps contracts closer to the model truth.
|
|
@@ -19,7 +19,7 @@ For contributor and automation workflows in this repository, prefer this order:
|
|
|
19
19
|
1. inspect the root `package.json` and `npm run vona` entrypoint
|
|
20
20
|
2. inspect Vona CLI command families such as `create:*`, `init:*`, `tools:*`, and `bin:*`
|
|
21
21
|
3. inspect the current module or suite layout before creating new files manually
|
|
22
|
-
4. use public docs for user-facing guidance
|
|
22
|
+
4. use public docs for user-facing and agent-facing guidance; consult an established internal-documentation home only when the active repository provides one for maintainer rationale
|
|
23
23
|
|
|
24
24
|
## Backend reading paths
|
|
25
25
|
|