cabloy 5.1.125 → 5.1.126
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/skills/cabloy-backend-scaffold/SKILL.md +1 -1
- package/.claude/skills/cabloy-backend-scaffold/evals/evals.json +6 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +13 -4
- package/.claude/skills/cabloy-workflow/SKILL.md +4 -2
- package/.claude/skills/cabloy-workflow/evals/evals.json +14 -2
- package/.claude/skills/cabloy-worktree-environment/SKILL.md +206 -0
- package/.claude/skills/cabloy-worktree-environment/evals/evals.json +77 -0
- package/.github/workflows/vona-test-pg.yml +3 -0
- package/.github/workflows/vona-test-sqlite3.yml +3 -0
- package/CHANGELOG.md +15 -0
- package/CLAUDE.md +1 -1
- package/cabloy-docs/.vitepress/config.mjs +1 -0
- package/cabloy-docs/backend/backend-contract-emission-specimen.md +2 -2
- package/cabloy-docs/backend/dto-guide.md +10 -7
- package/cabloy-docs/backend/dto-infer-generation.md +127 -7
- package/cabloy-docs/backend/foundation.md +1 -1
- package/cabloy-docs/backend/introduction.md +1 -0
- package/cabloy-docs/backend/module-dependencies.md +104 -0
- package/cabloy-docs/backend/serialization-guide.md +6 -0
- package/cabloy-docs/fullstack/parallel-worktree-environment.md +72 -34
- package/cabloy-docs/fullstack/suites-and-modules.md +1 -0
- package/cabloy-docs/reference/package-map.md +1 -0
- package/e2e/specs/a-commerce/commerce.spec.ts +89 -0
- package/package.json +2 -1
- package/scripts/init.ts +7 -12
- package/scripts/initAppName.test.ts +72 -0
- package/scripts/initAppName.ts +50 -0
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +27 -147
- package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineCreate.tsx +6 -27
- package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineItem.tsx +6 -31
- package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineUpdate.tsx +6 -2
- package/vona/src/suite/a-commerce/modules/commerce-member/src/lib/addressMine.ts +16 -0
- package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +4 -17
- package/vona/src/suite/a-commerce/modules/commerce-member/test/addressOwnership.test.ts +63 -19
- package/vona/src/suite/a-commerce/modules/commerce-payment/package.json +2 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +11 -2
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +26 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +19 -2
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/en-us.ts +5 -2
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/zh-cn.ts +5 -2
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateCreate.tsx +26 -35
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateUpdate.tsx +6 -1
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/entity/couponTemplate.tsx +40 -4
- package/vona/src/suite/a-commerce/modules/commerce-promotion/test/couponTemplateFormLayout.test.ts +85 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +1 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +3 -5
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSummary.tsx +7 -40
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/shipmentView.tsx +6 -15
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/lib/order.ts +9 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +121 -11
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/order.test.ts +25 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +19 -2
- package/vona/src/suite/a-training/modules/training-record/src/dto/detailRecordSubjectResItem.tsx +6 -1
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +3 -1
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +4 -1
- package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +45 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordResItem.tsx +6 -1
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +5 -23
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +37 -5
- package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +29 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +3 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.redlock.ts +3 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +7 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/queue.outboxDispatch.ts +9 -4
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +11 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/outboxEvent.tsx +11 -4
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +12 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/webhookInbox.tsx +6 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/outbox.ts +12 -5
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +1 -37
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +355 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +226 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +148 -50
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payScene.ts +2 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +39 -22
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +42 -13
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/controller/mockPayment.ts +11 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockRefundComplete.tsx +13 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockRefundReceipt.tsx +16 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +56 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +2 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +117 -8
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/package.json +5 -5
- package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoGet.ts +5 -5
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +54 -12
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +625 -64
- package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/types.ts +55 -15
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +15 -17
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +12 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +111 -26
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +3 -3
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +1 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +5 -9
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +1 -1
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +301 -17
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +5461 -1788
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.126
|
|
@@ -168,7 +168,7 @@ Then distinguish runtime lookup from a true module dependency:
|
|
|
168
168
|
- do not add a dependency declaration merely because code looks up another module's service, model, config, locale, or other resource
|
|
169
169
|
- scope lookup cannot make an absent module available; validate application/suite composition separately when the target must exist
|
|
170
170
|
|
|
171
|
-
For the canonical
|
|
171
|
+
For the canonical decision guide, read [Vona Module Dependencies](../../../cabloy-docs/backend/module-dependencies.md), with [Backend Foundation](../../../cabloy-docs/backend/foundation.md#scope-lookup-vs-module-dependencies) and [Package Map](../../../cabloy-docs/reference/package-map.md) as companions.
|
|
172
172
|
|
|
173
173
|
### Verification
|
|
174
174
|
|
|
@@ -24,6 +24,12 @@
|
|
|
24
24
|
"prompt": "I changed a model relation and some entity fields in Cabloy Basic. Before you tell me anything else, I want the Cabloy backend done-checklist, not a broad explanation of ORM theory.",
|
|
25
25
|
"expected_output": "Must give a concrete backend completion checklist, must include relation-aware follow-up and metadata or migration review, and must stay practical rather than drifting into generic ORM explanation.",
|
|
26
26
|
"files": []
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": 15,
|
|
30
|
+
"prompt": "My Vona service reads another module through this.$scope. Should I add vonaModule.dependencies? In a separate feature, my monkey.ts must extend a target module during startup. Explain the decision for both cases.",
|
|
31
|
+
"expected_output": "Must distinguish scope lookup from a module dependency edge, state that lookup alone does not require vonaModule.dependencies, and identify required availability, dependency-first ordering, or minimum compatible version as the criteria. Must recognize startup or monkey integration as a possible ordering case, verify composition separately, and reject speculative or circular edges.",
|
|
32
|
+
"files": []
|
|
27
33
|
}
|
|
28
34
|
]
|
|
29
35
|
}
|
|
@@ -14,6 +14,12 @@ After generating or extending a backend thread, check which follow-up layers app
|
|
|
14
14
|
- validation rules
|
|
15
15
|
- OpenAPI metadata
|
|
16
16
|
- inferred DTO opportunities
|
|
17
|
+
- treat `$Dto.get(...)` as the complete model-aware read shape by default; use `columns` or `dtoClass` only for a genuine business/query/response projection, not solely to remove `iid` or `deleted`
|
|
18
|
+
- treat the top-level `$Dto.create(...)` / `$Dto.update(...)` default omissions as a write-input authorization boundary, not as a reason to mechanically narrow ordinary `$Dto.get(...)` contracts
|
|
19
|
+
- when a narrowed DTO or OpenAPI schema is expected to remove physical response fields, separately shape and verify the action response; declaration narrowing alone does not guarantee runtime field stripping
|
|
20
|
+
- when stable Entity, Model, relation, or query truth exists, define the DTO projection first with `$Dto.*` and, where needed, `columns`, `include`, or `dtoClass`
|
|
21
|
+
- for an inferred field, use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement; use a class-body `@Api.field(...)` member only for a genuinely new field
|
|
22
|
+
- when inference cannot express the contract clearly, choose an explicit DTO deliberately; see [Default-first three-layer DTO authoring](../../../../cabloy-docs/backend/dto-infer-generation.md#default-first-three-layer-dto-authoring)
|
|
17
23
|
- frontend contract impact
|
|
18
24
|
- `@Api.field(...)` / `$makeSchema(...)` ordering: framework guards now preserve previously attached OpenAPI metadata across schema rebuilds, but structure-shaping schemaLike is still order-sensitive
|
|
19
25
|
- when an explicit zod/custom schema or other structure-defining schemaLike is present, put that structure-defining schemaLike last because `makeSchemaLikes(...)` applies arguments right-to-left and later structure changes can otherwise alter or replace the intended schema
|
|
@@ -50,10 +56,13 @@ After generating or extending a backend thread, check which follow-up layers app
|
|
|
50
56
|
|
|
51
57
|
## Module composition and dependency intent
|
|
52
58
|
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
59
|
+
- confirm package, suite, or application composition already supplies a target before using cross-module lookup; lookup cannot compose an absent module
|
|
60
|
+
- choose the narrowest lookup form first: `this.scope` for local resources, `this.$scope.<module>` for a fixed cross-module target, and `app.scope(...)` when an application reference or genuinely dynamic target is required
|
|
61
|
+
- cross-module scope lookup, a named ORM relation, or `$Dto.get(..., { include })` alone does not require `vonaModule.dependencies`
|
|
62
|
+
- add `vonaModule.dependencies` only for a genuine target-module availability, dependency-first ordering, or minimum-version requirement
|
|
63
|
+
- startup, lifecycle, or `monkey.ts` integration can require dependency-first ordering, but are not the only valid dependency case
|
|
64
|
+
- when adding an edge, verify package/suite composition, the target relative module name, the minimum compatible version, and that the graph remains acyclic
|
|
65
|
+
- do not create speculative dependency edges or circular declarations merely to document a lookup; read [Vona Module Dependencies](../../../../cabloy-docs/backend/module-dependencies.md) for the canonical decision guide
|
|
57
66
|
|
|
58
67
|
## Verification follow-up
|
|
59
68
|
|
|
@@ -100,9 +100,11 @@ The reason is simple: these files are where Cabloy already encodes its real work
|
|
|
100
100
|
|
|
101
101
|
### Parallel worktree environment setup
|
|
102
102
|
|
|
103
|
-
When a request involves a second worktree, concurrent Vona/Zova development, isolated ordinary tests, or managed clean E2E, classify it as fullstack workflow setup. Read [Parallel Worktree Environment](../../../cabloy-docs/fullstack/parallel-worktree-environment.md)
|
|
103
|
+
When a request involves a second worktree, concurrent Vona/Zova development, isolated ordinary tests, or managed clean E2E, classify it as fullstack workflow setup. Read [Parallel Worktree Environment](../../../cabloy-docs/fullstack/parallel-worktree-environment.md), the canonical shared recipe maintained in Cabloy Basic for both editions.
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
This routing skill provides read-only guidance only. Do not infer an `APP_NAME` or ports, edit local overrides, or run `npm run init` from a generic worktree request. When the user wants confirmation-gated local environment setup, ask them to explicitly invoke `/cabloy-worktree-environment`.
|
|
106
|
+
|
|
107
|
+
The invoked skill detects Basic or Start to select the active root scripts and managed clean-E2E command. It uses Git worktree metadata, fixed Vona/Zova port baselines, and the worktree basename to recommend the complete standard tuple for confirmation: `APP_NAME`, `SERVER_LISTEN_PORT`, `DEV_SERVER_PORT`, `DEV_SERVER_HMR_PORT`, and an `API_BASE_URL` derived from the Vona port. After confirmation, it writes both `vona/env/.env.local` and `zova/env/.env.local`; never use flavor-, mode-, app-mode-, or runtime-specific `.env.*.local` files. It does not inspect environment-file content or allocate/reserve a live port. The shared environment is Vona + Zova development: Admin and Web are alternative commands using the same configuration, and they must not run concurrently in one worktree. Concurrent use requires separately configured linked worktrees.
|
|
106
108
|
|
|
107
109
|
## Step 4: Prefer CLI-first workflows
|
|
108
110
|
|
|
@@ -33,8 +33,20 @@
|
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"id": 6,
|
|
36
|
-
"prompt": "I created a second Cabloy Basic worktree and need to run Vona, Zova, and test:e2e:basic:clean in parallel with the first worktree. Which environment files and exact variables should I configure without changing shared defaults?",
|
|
37
|
-
"expected_output": "Classifies this as fullstack parallel-worktree environment setup and routes to the canonical Parallel Worktree Environment guide.
|
|
36
|
+
"prompt": "I created a second Cabloy Basic worktree and need to run Vona, Zova Admin, and test:e2e:basic:clean in parallel with the first worktree. Which environment files and exact variables should I configure without changing shared defaults?",
|
|
37
|
+
"expected_output": "Classifies this as fullstack parallel-worktree environment setup and routes to the canonical shared Parallel Worktree Environment guide. Explains that generic routing is read-only: it must not inspect env content, infer or write local values, or run npm run init. Directs the user to explicitly invoke /cabloy-worktree-environment for confirmation-gated setup. The invoked skill uses Git worktree metadata, the worktree basename, and fixed baseline ports to recommend APP_NAME, SERVER_LISTEN_PORT, DEV_SERVER_PORT, DEV_SERVER_HMR_PORT, and a derived API_BASE_URL, then writes only vona/env/.env.local and zova/env/.env.local after confirmation. It does not use a flavor-specific local file or reserve ports; Admin and Web are alternative non-concurrent commands using the shared tuple.",
|
|
38
|
+
"files": []
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": 7,
|
|
42
|
+
"prompt": "I created a linked Cabloy Start worktree and need isolated Vona, Zova Web, and managed clean E2E. Which workflow should I use?",
|
|
43
|
+
"expected_output": "Routes to the canonical shared guide and explicitly invoked /cabloy-worktree-environment skill. It recognizes that the invoked skill selects the Start command npm run test:e2e:start:clean while retaining read-only generic routing, a deterministic Git-metadata recommendation, no environment-content inspection, no automatic initialization, and the universal five-setting tuple written to both permitted broad local files only after confirmation.",
|
|
44
|
+
"files": []
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 8,
|
|
48
|
+
"prompt": "I created a linked Cabloy Basic worktree and only need backend tests. What should I do for local environment isolation?",
|
|
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.",
|
|
38
50
|
"files": []
|
|
39
51
|
}
|
|
40
52
|
]
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cabloy-worktree-environment
|
|
3
|
+
description: This skill must be used only when the user explicitly invokes /cabloy-worktree-environment or explicitly asks to perform the named Cabloy worktree-environment setup. It prepares a confirmation-gated, worktree-local Vona and Zova runtime environment for a linked Cabloy Basic or Cabloy Start Git worktree using Git metadata and fixed port baselines only. Do not use it merely because a request mentions worktrees, parallel work, ports, development, tests, or E2E; route those requests to cabloy-workflow for read-only guidance instead.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cabloy Worktree Environment
|
|
7
|
+
|
|
8
|
+
Use this skill only for explicit, user-controlled setup of the standard local runtime environment in an already-created linked Git worktree.
|
|
9
|
+
|
|
10
|
+
## Goals
|
|
11
|
+
|
|
12
|
+
1. validate that the current checkout is a linked Cabloy Basic or Cabloy Start worktree before any write
|
|
13
|
+
2. generate a deterministic, secret-safe core environment tuple from Git worktree metadata and fixed port baselines
|
|
14
|
+
3. never read, parse, source, expand, display, log, or send `.env*` file contents to the model
|
|
15
|
+
4. write only a new or empty `vona/env/.env.local` and `zova/env/.env.local` in the current worktree after explicit confirmation
|
|
16
|
+
5. keep Admin and Web as alternative runtime commands that share one generated Zova configuration
|
|
17
|
+
6. keep `npm run init` a separate, opt-in decision
|
|
18
|
+
|
|
19
|
+
## Step 1: Validate the current checkout and edition
|
|
20
|
+
|
|
21
|
+
Before proposing configuration values or writing files:
|
|
22
|
+
|
|
23
|
+
1. resolve the current absolute Git top-level directory
|
|
24
|
+
2. run `git worktree list --porcelain -z` and parse its NUL-delimited records without shell word splitting
|
|
25
|
+
3. verify that the current root is registered
|
|
26
|
+
4. compare absolute `git-dir` and `git-common-dir`; equal paths identify the primary checkout, which this skill must reject
|
|
27
|
+
5. detect exactly one edition marker at the resolved root
|
|
28
|
+
6. verify that `vona/env/`, `zova/env/`, and the required root scripts exist
|
|
29
|
+
|
|
30
|
+
Interpretation:
|
|
31
|
+
|
|
32
|
+
| Marker | Edition | Managed clean E2E command |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `__CABLOY_BASIC__` only | Cabloy Basic | `npm run test:e2e:basic:clean` |
|
|
35
|
+
| `__CABLOY_START__` only | Cabloy Start | `npm run test:e2e:start:clean` |
|
|
36
|
+
|
|
37
|
+
Stop without edits when both markers are present, neither marker is present, the checkout is primary/unregistered, required environment directories are missing, or the selected edition's required scripts are unavailable.
|
|
38
|
+
|
|
39
|
+
Read [Parallel Worktree Environment](../../../cabloy-docs/fullstack/parallel-worktree-environment.md) as the canonical shared recipe. Edition detection chooses command names and labels; it does not change the two-file environment model. Never change committed defaults, including `vona/env/.env` and `zova/env/.env`.
|
|
40
|
+
|
|
41
|
+
## Step 2: Generate the standard environment recommendation
|
|
42
|
+
|
|
43
|
+
After validation, immediately generate the standard core tuple. Do not ask which processes the user intends to run and do not ask them to select Admin or Web.
|
|
44
|
+
|
|
45
|
+
For user-facing summaries, write exactly:
|
|
46
|
+
|
|
47
|
+
> 环境隔离信息:Vona 开发 + Zova 开发
|
|
48
|
+
|
|
49
|
+
Admin and Web use this same Zova environment. The user may later run either frontend command, but must not run both concurrently in one worktree. Use another linked worktree for concurrent development of the other flavor. Do not create a flavor-specific local override.
|
|
50
|
+
|
|
51
|
+
### Secret-safe input boundary
|
|
52
|
+
|
|
53
|
+
Recommendation generation uses Git worktree metadata and the fixed constants below only. It must not inspect any `.env`, `.env.local`, `.env.*.local`, sibling worktree configuration, process environment, listener table, `lsof` output, process command line, or external service. Do not use `Read`, `cat`, `grep`, `source`, `dotenv`, `printenv`, `env`, or diagnostics that expose env-file content for this workflow.
|
|
54
|
+
|
|
55
|
+
This means the proposal is deterministic convenience, not a live port reservation. If an application later reports a port collision, the user may say **“再换一批”** before setup or create another linked worktree; the actual application bind remains authoritative.
|
|
56
|
+
|
|
57
|
+
### Deterministic proposal
|
|
58
|
+
|
|
59
|
+
Treat the primary checkout as ordinal `0`. From the validated `git worktree list --porcelain -z` order, assign each linked worktree the next ordinal: the first linked worktree is `1`, the second is `2`, and so on. Let `batch` be `0` for the first proposal, and increase it only when the user says **“再换一批”**.
|
|
60
|
+
|
|
61
|
+
Use one shared offset for every generated listener:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
offset = linkedWorktreeOrdinal + batch
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Use these fixed baseline ports, which match the committed Cabloy defaults:
|
|
68
|
+
|
|
69
|
+
| Setting | Baseline | Recommended value |
|
|
70
|
+
| --- | ---: | --- |
|
|
71
|
+
| `SERVER_LISTEN_PORT` | `7102` | `7102 + offset` |
|
|
72
|
+
| `DEV_SERVER_PORT` | `9000` | `9000 + offset` |
|
|
73
|
+
| `DEV_SERVER_HMR_PORT` | `24679` | `24679 + offset` |
|
|
74
|
+
|
|
75
|
+
Set `APP_NAME` to the basename of the validated current worktree root. Do not inspect other worktrees’ configurations or append an env-derived suffix. Stop if that basename is empty or cannot be used as an application name without altering it; ask the user to rename/recreate the linked worktree instead.
|
|
76
|
+
|
|
77
|
+
Always recommend both local files:
|
|
78
|
+
|
|
79
|
+
```dotenv
|
|
80
|
+
# vona/env/.env.local
|
|
81
|
+
APP_NAME = <worktree-basename>
|
|
82
|
+
SERVER_LISTEN_PORT = <7102 + offset>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```dotenv
|
|
86
|
+
# zova/env/.env.local
|
|
87
|
+
APP_NAME = <worktree-basename>
|
|
88
|
+
API_BASE_URL = http://localhost:<recommended SERVER_LISTEN_PORT>
|
|
89
|
+
DEV_SERVER_PORT = <9000 + offset>
|
|
90
|
+
DEV_SERVER_HMR_PORT = <24679 + offset>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
All generated listener ports must be integers from `1` through `65535` and distinct within the tuple. If a batch would exceed that range, stop and require a different linked-worktree arrangement.
|
|
94
|
+
|
|
95
|
+
When the user says **“再换一批”**, set `batch = batch + 1`, recompute the entire tuple, and show it again. Every recommended listener advances by exactly `+1`, and `API_BASE_URL` is regenerated from the new Vona port. Do not write during a batch change. This deterministic setup does not accept user-substituted values.
|
|
96
|
+
|
|
97
|
+
A unique `APP_NAME` separates ordinary framework-managed test database names and framework Redis prefixes. It does not isolate explicitly named databases, unprefixed custom Redis keys, mail, payment, webhooks, object storage, or other external services. Require a separate explicit design before claiming that any of those resources are isolated.
|
|
98
|
+
|
|
99
|
+
## Step 3: Preview and confirm the write
|
|
100
|
+
|
|
101
|
+
Before making any edit:
|
|
102
|
+
|
|
103
|
+
1. show `环境隔离信息:Vona 开发 + Zova 开发`, the worktree ordinal, batch, and exact non-secret identity/port tuple
|
|
104
|
+
2. show a file-by-file preview containing only the managed assignments that will be written to both broad local files
|
|
105
|
+
3. run one independent `git check-ignore -v -- "$target"` command for each target and require each command to succeed with a matching ignore rule
|
|
106
|
+
4. recheck current root, linked-worktree identity, edition, ordinal, generated port range, tuple uniqueness, and both target states
|
|
107
|
+
5. ask for a final affirmative confirmation that includes the proposed identity and port tuple
|
|
108
|
+
|
|
109
|
+
Do not treat silence as confirmation.
|
|
110
|
+
|
|
111
|
+
## Step 4: Apply only safe broad local overrides
|
|
112
|
+
|
|
113
|
+
The only files this skill may create or change are:
|
|
114
|
+
|
|
115
|
+
- `vona/env/.env.local`
|
|
116
|
+
- `zova/env/.env.local`
|
|
117
|
+
|
|
118
|
+
To preserve the no-env-content-disclosure boundary, inspect only each target's existence and whether it is empty; do not read its contents. If either target already exists and is non-empty, stop without reading or modifying either file. Explain that this skill deliberately will not access a pre-existing local environment file because it may contain secrets; the user must manage it outside this workflow or use a fresh linked worktree.
|
|
119
|
+
|
|
120
|
+
Only after final confirmation:
|
|
121
|
+
|
|
122
|
+
1. immediately re-run one independent `git check-ignore -v -- "$target"` command for each target and abort unless each succeeds with a matching ignore rule
|
|
123
|
+
2. confirm both targets are absent or empty without reading their content
|
|
124
|
+
3. snapshot only each target's existence and empty-file state
|
|
125
|
+
4. write the exact previewed Vona assignments to `vona/env/.env.local`
|
|
126
|
+
5. write the exact previewed Zova assignments to `zova/env/.env.local`
|
|
127
|
+
6. do not create, modify, remove, inspect, or recommend flavor-, mode-, app-mode-, or runtime-specific `.env.*.local` files
|
|
128
|
+
|
|
129
|
+
Never:
|
|
130
|
+
|
|
131
|
+
- edit another worktree
|
|
132
|
+
- read, parse, source, expand, display, or log existing environment-file content
|
|
133
|
+
- edit committed `.env` defaults
|
|
134
|
+
- add mock, preview, or other runtime-specific listener settings through this workflow
|
|
135
|
+
- claim that a deterministic recommendation has allocated or reserved a port
|
|
136
|
+
- generate values or write configuration merely to bypass a busy shared resource
|
|
137
|
+
|
|
138
|
+
If a write cannot complete, restore each already changed target to its exact prior state: remove a newly created target or restore an originally empty target to an empty file. Report only the path and operation stage; never include environment-file content in the failure output.
|
|
139
|
+
|
|
140
|
+
## Step 5: Revalidate and offer initialization separately
|
|
141
|
+
|
|
142
|
+
After writing, verify only the known assignments that this skill generated and wrote, without re-reading any pre-existing local content. Confirm:
|
|
143
|
+
|
|
144
|
+
- the generated Vona and Zova `APP_NAME` values match
|
|
145
|
+
- `API_BASE_URL` targets the generated Vona port
|
|
146
|
+
- `SERVER_LISTEN_PORT`, `DEV_SERVER_PORT`, and `DEV_SERVER_HMR_PORT` are distinct
|
|
147
|
+
- both target paths and edition commands remain valid
|
|
148
|
+
|
|
149
|
+
Report only the files changed, the generated non-secret tuple, and external resources that remain shared.
|
|
150
|
+
|
|
151
|
+
Then ask exactly:
|
|
152
|
+
|
|
153
|
+
> The local environment overrides are configured. Do you want to run `npm run init` now?
|
|
154
|
+
|
|
155
|
+
Do not run it without an affirmative answer. Explain that `npm run init` is not an environment allocator: it installs dependencies and runs generation/build-related work. In this linked worktree, it preserves the tracked base `APP_NAME` defaults in `vona/env/.env` and `zova/env/.env`; the generated broad `.env.local` files remain the worktree-specific identity source. Primary-checkout and non-Git project initialization may still establish base `APP_NAME` from the project directory.
|
|
156
|
+
|
|
157
|
+
## Verification
|
|
158
|
+
|
|
159
|
+
Use focused checks appropriate to the detected edition:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git worktree list --porcelain -z
|
|
163
|
+
git rev-parse --path-format=absolute --show-toplevel
|
|
164
|
+
git rev-parse --path-format=absolute --git-dir
|
|
165
|
+
git rev-parse --path-format=absolute --git-common-dir
|
|
166
|
+
for target in vona/env/.env.local zova/env/.env.local; do
|
|
167
|
+
git check-ignore -v -- "$target" || exit 1
|
|
168
|
+
done
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Run one frontend command, not both:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm run dev
|
|
175
|
+
npm run dev:zova:admin
|
|
176
|
+
# or
|
|
177
|
+
npm run dev:zova:web
|
|
178
|
+
npm run test
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Run the edition-appropriate managed clean E2E command:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Cabloy Basic
|
|
185
|
+
npm run test:e2e:basic:clean
|
|
186
|
+
|
|
187
|
+
# Cabloy Start
|
|
188
|
+
npm run test:e2e:start:clean
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Finish with a metadata-only status check. Do not use `git diff`, because it can print environment-file content:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
git status --short
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Response pattern
|
|
198
|
+
|
|
199
|
+
When this skill completes a stage, report:
|
|
200
|
+
|
|
201
|
+
1. validated worktree root and detected edition
|
|
202
|
+
2. `环境隔离信息:Vona 开发 + Zova 开发`
|
|
203
|
+
3. worktree ordinal, batch, and generated non-secret identity/ports
|
|
204
|
+
4. both exact broad local files proposed or changed
|
|
205
|
+
5. the privacy boundary and external resources that still require separate isolation
|
|
206
|
+
6. the separate `npm run init` question only after successful local setup
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "cabloy-worktree-environment",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in the first linked Cabloy Basic worktree. Configure the local environment.",
|
|
7
|
+
"expected_output": "Validates that the current checkout is a linked Cabloy Basic worktree before any write. Without asking which processes or frontend flavor will run, it uses Git worktree metadata only and recommends APP_NAME from the worktree basename, SERVER_LISTEN_PORT 7103, DEV_SERVER_PORT 9001, DEV_SERVER_HMR_PORT 24680, and API_BASE_URL http://localhost:7103. It labels the configuration as 环境隔离信息:Vona 开发 + Zova 开发, previews both vona/env/.env.local and zova/env/.env.local, waits for final confirmation before writing, and separately asks whether to run npm run init after success.",
|
|
8
|
+
"files": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in the second linked Cabloy Start worktree. Set up the standard local environment.",
|
|
13
|
+
"expected_output": "Detects __CABLOY_START__, selects npm run test:e2e:start:clean for later verification, and uses the shared canonical workflow. Without a process-selection question, it derives APP_NAME from the worktree basename and, for ordinal 2 batch 0, recommends SERVER_LISTEN_PORT 7104, DEV_SERVER_PORT 9002, DEV_SERVER_HMR_PORT 24681, and API_BASE_URL http://localhost:7104. It uses only the two broad local targets and waits for final confirmation before writing both.",
|
|
14
|
+
"files": []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 3,
|
|
18
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment from the primary Cabloy Basic checkout. Set up a second local runtime here so I can avoid the port already in use.",
|
|
19
|
+
"expected_output": "Rejects the request without writing because the current checkout is the primary checkout rather than a linked worktree. It does not modify shared identity or ports merely to bypass a busy resource.",
|
|
20
|
+
"files": []
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": 4,
|
|
24
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in a linked Cabloy Basic worktree. I only plan to run ordinary backend tests.",
|
|
25
|
+
"expected_output": "Does not ask the user to select processes and still recommends the universal five-setting tuple: worktree-basename APP_NAME, SERVER_LISTEN_PORT, DEV_SERVER_PORT, DEV_SERVER_HMR_PORT, and an API_BASE_URL derived from the server port. After confirmation it writes both vona/env/.env.local and zova/env/.env.local, while explaining that external services require separate isolation decisions.",
|
|
26
|
+
"files": []
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": 5,
|
|
30
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in a linked Cabloy Basic worktree and later want to use Admin and Web frontend commands.",
|
|
31
|
+
"expected_output": "Generates the same shared standard tuple without asking for a frontend flavor and never proposes a flavor-specific .env.XXX.local file. It explains that Admin and Web use the generated Zova configuration but must not run concurrently in one worktree; another linked worktree is required for concurrent use.",
|
|
32
|
+
"files": []
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": 6,
|
|
36
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in a linked Cabloy Start worktree and also intend to use SSR preview later.",
|
|
37
|
+
"expected_output": "Generates only the universal five-setting Vona and Zova tuple in the two broad local files. It does not add MOCK_BUILD_PORT, SSR_PROD_PORT, SSR_API_BASE_URL, or another runtime-specific local file; those require a separately designed workflow.",
|
|
38
|
+
"files": []
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": 7,
|
|
42
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in a linked Cabloy Basic worktree, but zova/env/.env.local is tracked or not ignored.",
|
|
43
|
+
"expected_output": "Runs an independent git check-ignore -v -- target command for both broad targets and rejects the write before confirmation because every target must be ignored. It does not fall back to a specific local file or modify the tracked target.",
|
|
44
|
+
"files": []
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 8,
|
|
48
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in the first linked Cabloy Basic worktree. The initial proposal is 7103, 9001, and 24680. 再换一批。",
|
|
49
|
+
"expected_output": "Keeps the same worktree APP_NAME, increases the shared batch by one, and proposes SERVER_LISTEN_PORT 7104, DEV_SERVER_PORT 9002, DEV_SERVER_HMR_PORT 24681, and API_BASE_URL http://localhost:7104. It does not write, inspect ports, inspect environment files, or treat either batch as reserved before final confirmation.",
|
|
50
|
+
"files": []
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": 9,
|
|
54
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment for a linked Cabloy Basic worktree. My local .env.local files may contain credentials. Set up the standard local environment.",
|
|
55
|
+
"expected_output": "Uses only Git worktree metadata, fixed port baselines, and the worktree basename. It does not read, parse, source, expand, print, log, or send any .env* contents, process environment, listener table, or sibling configuration to the model. If either target broad local file exists and is non-empty at the confirmed write stage, it stops without reading or modifying either file.",
|
|
56
|
+
"files": []
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": 10,
|
|
60
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment for a linked Cabloy Basic worktree. Writing zova/env/.env.local fails after vona/env/.env.local was created.",
|
|
61
|
+
"expected_output": "Uses only absent or empty permitted targets, snapshots their existence and empty-file state without reading content, removes every target newly created during the failed operation, restores any originally empty target to empty state, and reports the failure without leaving a partial configuration or exposing environment-file content.",
|
|
62
|
+
"files": []
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": 11,
|
|
66
|
+
"prompt": "/cabloy-worktree-environment",
|
|
67
|
+
"expected_output": "After validating that the current checkout is a linked Cabloy worktree, immediately proposes the complete universal tuple and previews both broad local files. It does not ask the user to choose Vona, tests, E2E, Admin, or Web before the final confirmation.",
|
|
68
|
+
"files": []
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": 12,
|
|
72
|
+
"prompt": "I confirm the proposed standard tuple in a valid linked worktree.",
|
|
73
|
+
"expected_output": "Rechecks ignore rules and absent-or-empty state for both permitted targets, then writes vona/env/.env.local and zova/env/.env.local together. It validates their generated assignments without reading prior content and only then asks the exact separate npm run init question.",
|
|
74
|
+
"files": []
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
@@ -34,6 +34,9 @@ jobs:
|
|
|
34
34
|
version: 11.5.2
|
|
35
35
|
- name: init
|
|
36
36
|
run: npm run init
|
|
37
|
+
- name: run A-Pay focused gate
|
|
38
|
+
run: DATABASE_DEFAULT_CLIENT=pg npm run vona :bin:test -- test-pay/test/paymentSession.test.ts test-pay/test/payMock.test.ts test-pay/test/outbox.test.ts test-pay/test/webhook.test.ts --flavor=normal
|
|
39
|
+
working-directory: vona
|
|
37
40
|
- name: run Commerce stock contention gate
|
|
38
41
|
run: |
|
|
39
42
|
DATABASE_DEFAULT_CLIENT=pg npm run vona :bin:test -- commerce-trade/test/stockBalance.test.ts commerce-trade/test/stockReservation.test.ts commerce-trade/test/stockAudit.test.ts --flavor=normal
|
|
@@ -27,6 +27,9 @@ jobs:
|
|
|
27
27
|
version: 11.5.2
|
|
28
28
|
- name: init
|
|
29
29
|
run: npm run init
|
|
30
|
+
- name: run A-Pay focused gate
|
|
31
|
+
run: DATABASE_DEFAULT_CLIENT=sqlite3 npm run vona :bin:test -- test-pay/test/paymentSession.test.ts test-pay/test/payMock.test.ts test-pay/test/outbox.test.ts test-pay/test/webhook.test.ts --flavor=normal
|
|
32
|
+
working-directory: vona
|
|
30
33
|
- name: run Commerce payment, shipment, and refund lifecycle gate
|
|
31
34
|
run: DATABASE_DEFAULT_CLIENT=sqlite3 npm run vona :bin:test -- commerce-trade/test/paymentOutcome.test.ts commerce-trade/test/reservationExpiry.test.ts commerce-trade/test/shipment.test.ts commerce-trade/test/refundLifecycle.test.ts --flavor=normal
|
|
32
35
|
working-directory: vona
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.126
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add and update skills for the cabloy worktree environment.
|
|
8
|
+
- Add payment capabilities and related tests.
|
|
9
|
+
- Add DTO inference support.
|
|
10
|
+
- Add `$Dto.get` rules.
|
|
11
|
+
- Update application capabilities and workflows.
|
|
12
|
+
|
|
13
|
+
### Improvements
|
|
14
|
+
|
|
15
|
+
- Refactor DTO inference handling.
|
|
16
|
+
- Refactor training-related modules.
|
|
17
|
+
|
|
3
18
|
## 5.1.125
|
|
4
19
|
|
|
5
20
|
### Features
|
package/CLAUDE.md
CHANGED
|
@@ -58,7 +58,7 @@ Before inventing a custom implementation path:
|
|
|
58
58
|
- 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.
|
|
59
59
|
- 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.
|
|
60
60
|
- Keep repo-wide AI rules in `CLAUDE.md` short and durable; put branching Zova analysis workflows in `.claude/skills/`.
|
|
61
|
-
- Do not modify shared environment identity or ports merely to bypass a busy resource. For intentional parallel worktree setup, follow `cabloy-docs/fullstack/parallel-worktree-environment.md`; otherwise wait for the shared resource or ask the user.
|
|
61
|
+
- Do not modify shared environment identity or ports merely to bypass a busy resource. For intentional parallel worktree setup, follow `cabloy-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.
|
|
62
62
|
- For SSR theme-sensitive frontend work, detect the active edition marker and UI library before making assumptions. Cabloy Basic currently means DaisyUI + Tailwind CSS assumptions; Cabloy Start currently means Vuetify assumptions.
|
|
63
63
|
- In Web SSR without cookie-backed theme resolution, do not treat server reads of `$theme.dark`, `$theme.darkMode`, or `$token` as final browser truth. Keep theme-sensitive SSR branching hydration-tolerant or defer final theme-sensitive decisions to the client.
|
|
64
64
|
- Do not assume Cabloy Basic and Cabloy Start use the same adapter-level SSR theme handoff. Verify the active theme handler and client hydration path before changing SSR theme behavior.
|
|
@@ -198,6 +198,7 @@ export default defineConfig({
|
|
|
198
198
|
items: [
|
|
199
199
|
{ text: 'Introduction', link: '/backend/introduction' },
|
|
200
200
|
{ text: 'Foundation', link: '/backend/foundation' },
|
|
201
|
+
{ text: 'Module Dependencies', link: '/backend/module-dependencies' },
|
|
201
202
|
{ text: 'Backend Essentials', link: '/backend/backend-essentials' },
|
|
202
203
|
{ text: 'Quickstart', link: '/backend/quickstart' },
|
|
203
204
|
{
|
|
@@ -101,8 +101,8 @@ The next source to read is:
|
|
|
101
101
|
Representative source facts:
|
|
102
102
|
|
|
103
103
|
- `@Dto<IDtoOptionsStudentSummary>()`
|
|
104
|
-
-
|
|
105
|
-
- `@Api.field(...)` metadata
|
|
104
|
+
- the `ModelStudent` projection supplies `id`, `name`, `mobile`, `level`, and `description`
|
|
105
|
+
- direct `@Api.field(...)` metadata declares the computed `levelTitle`, `descriptionLength`, and `summaryText` fields
|
|
106
106
|
|
|
107
107
|
This file answers the second emission question:
|
|
108
108
|
|
|
@@ -148,7 +148,9 @@ A practical split is:
|
|
|
148
148
|
- use inferred DTOs when the contract closely follows model structure or query shape
|
|
149
149
|
- wrap inferred DTOs in a named DTO class when reuse or discoverability becomes more important
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
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; add an `@Api.field(...)` member only for a genuinely new field absent from the inferred contract. Keep an explicit DTO as a deliberate fallback when no suitable upstream truth exists or the inferred composition is less clear.
|
|
152
|
+
|
|
153
|
+
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).
|
|
152
154
|
|
|
153
155
|
## Relationship to ORM and controller contracts
|
|
154
156
|
|
|
@@ -166,12 +168,13 @@ That means DTO design should often be read together with:
|
|
|
166
168
|
|
|
167
169
|
When creating DTOs:
|
|
168
170
|
|
|
169
|
-
1.
|
|
170
|
-
2.
|
|
171
|
-
3.
|
|
172
|
-
4.
|
|
173
|
-
5.
|
|
174
|
-
6.
|
|
171
|
+
1. check whether an Entity, Model, relation, or query shape already provides suitable upstream contract truth
|
|
172
|
+
2. define the inferred projection before redeclaring fields: choose the `$Dto.*` helper and, where needed, `columns`, `include`, or `dtoClass`
|
|
173
|
+
3. use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement of an inferred field
|
|
174
|
+
4. use `@Api.field(...)` for a genuinely new field, not as a second declaration of an inferred field
|
|
175
|
+
5. keep DTO validation and OpenAPI concerns aligned, and keep the final structure-defining schema last when using schema-like composition
|
|
176
|
+
6. decide whether the contract should remain inferred, be wrapped in a named inferred DTO, or deliberately fall back to an explicit DTO
|
|
177
|
+
7. treat DTO design as part of the contract between backend handlers, models, and frontend integration
|
|
175
178
|
|
|
176
179
|
## Where to read next
|
|
177
180
|
|