cabloy 5.1.124 → 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 +21 -0
- package/CLAUDE.md +1 -1
- package/cabloy-docs/.vitepress/config.mjs +2 -0
- package/cabloy-docs/ai/playbook-technical-blog-authoring.md +158 -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 +48 -146
- 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/vona/src/suite-vendor/a-pay/modules/a-pay/test/outbox.test.ts +0 -209
- package/vona/src/suite-vendor/a-pay/modules/a-pay/test/paymentSession.test.ts +0 -153
- package/vona/src/suite-vendor/a-pay/modules/a-pay/test/webhook.test.ts +0 -278
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/test/payMock.test.ts +0 -141
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,26 @@
|
|
|
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
|
+
|
|
18
|
+
## 5.1.125
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
- Update payment functionality.
|
|
23
|
+
|
|
3
24
|
## 5.1.124
|
|
4
25
|
|
|
5
26
|
### Improvements
|
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.
|
|
@@ -25,6 +25,7 @@ const aiItems = [
|
|
|
25
25
|
{ text: 'Playbook: Contract Regeneration', link: '/ai/playbook-contract-regeneration' },
|
|
26
26
|
{ text: 'Playbook: Module Removal', link: '/ai/playbook-module-removal' },
|
|
27
27
|
{ text: 'Playbook: Metadata Refresh', link: '/ai/playbook-metadata-refresh' },
|
|
28
|
+
{ text: 'Playbook: Technical Blog Authoring', link: '/ai/playbook-technical-blog-authoring' },
|
|
28
29
|
{ text: 'CLI for Agents', link: '/ai/cli-for-agents' },
|
|
29
30
|
{ text: 'Rules and Config', link: '/ai/rules-and-config' },
|
|
30
31
|
{ text: 'Edition Detection', link: '/ai/edition-detection' },
|
|
@@ -197,6 +198,7 @@ export default defineConfig({
|
|
|
197
198
|
items: [
|
|
198
199
|
{ text: 'Introduction', link: '/backend/introduction' },
|
|
199
200
|
{ text: 'Foundation', link: '/backend/foundation' },
|
|
201
|
+
{ text: 'Module Dependencies', link: '/backend/module-dependencies' },
|
|
200
202
|
{ text: 'Backend Essentials', link: '/backend/backend-essentials' },
|
|
201
203
|
{ text: 'Quickstart', link: '/backend/quickstart' },
|
|
202
204
|
{
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Playbook: Technical Blog Authoring
|
|
2
|
+
|
|
3
|
+
Use this playbook when writing a technical blog about Cabloy, Vona, Zova, or an adjacent engineering problem. Its purpose is to help authors and agents turn a real reader concern into an accurate, approachable, and useful article.
|
|
4
|
+
|
|
5
|
+
A blog post is not a replacement for reference documentation. Use the post to establish a mental model, explain why a design choice matters, and help readers choose a next step. Link to the relevant documentation for the complete contract and implementation detail.
|
|
6
|
+
|
|
7
|
+
## Start with the reader's problem
|
|
8
|
+
|
|
9
|
+
Open with a problem that readers can recognize in their existing practice, not with framework terminology or a product claim.
|
|
10
|
+
|
|
11
|
+
For example, a Vue-oriented article can begin with a reader encountering growing composables, fragmented state ownership, or unclear cache invalidation. It should acknowledge that the familiar tools are useful before explaining the architectural tradeoff they do not settle by themselves.
|
|
12
|
+
|
|
13
|
+
Then state one narrow thesis. A useful thesis does all of the following:
|
|
14
|
+
|
|
15
|
+
- names the change in perspective;
|
|
16
|
+
- limits what the article claims;
|
|
17
|
+
- avoids declaring one ecosystem universally superior.
|
|
18
|
+
|
|
19
|
+
For example:
|
|
20
|
+
|
|
21
|
+
> Zova retains Vue 3 as its reactive foundation while giving complex application code explicit owners for state, behavior, dependencies, and lifecycle.
|
|
22
|
+
|
|
23
|
+
Do not begin with claims such as “Framework X is obsolete,” “this is the only correct architecture,” or broad adoption and performance claims that the article cannot prove.
|
|
24
|
+
|
|
25
|
+
## Research before drafting
|
|
26
|
+
|
|
27
|
+
Use this authority order for technical claims:
|
|
28
|
+
|
|
29
|
+
1. Current Cabloy documentation, source code, and tests for Cabloy, Vona, and Zova behavior.
|
|
30
|
+
2. First-party upstream documentation for Vue, TypeScript, TanStack Query, React, Angular, or another external ecosystem.
|
|
31
|
+
3. Carefully labelled experience, interpretation, and recommendations when a fact cannot be established from the sources above.
|
|
32
|
+
|
|
33
|
+
Treat legacy documentation as input material, not unquestioned truth. If it conflicts with current source, prefer the source.
|
|
34
|
+
|
|
35
|
+
Classify each meaningful statement while drafting:
|
|
36
|
+
|
|
37
|
+
| Statement type | How to write it |
|
|
38
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| Verified framework fact | State it precisely and link to current public docs or an authoritative upstream source. |
|
|
40
|
+
| Comparison or interpretation | Explain the authoring-model difference with qualified wording such as “typically,” “can,” or “is designed to.” |
|
|
41
|
+
| Experience or recommendation | Make its situational nature visible: “consider this when…”, “can be a good fit for…”, or “in this kind of project…”. |
|
|
42
|
+
|
|
43
|
+
Do not turn a representative example, a personal observation, or a framework goal into a universal ecosystem claim.
|
|
44
|
+
|
|
45
|
+
## Use a problem-to-practice narrative
|
|
46
|
+
|
|
47
|
+
For beginner-oriented technical posts, use this progression:
|
|
48
|
+
|
|
49
|
+
1. **Reader problem** — establish empathy with a concrete, familiar situation.
|
|
50
|
+
2. **Mental-model shift** — introduce one focused thesis that reframes the problem.
|
|
51
|
+
3. **Progressive examples** — teach one concept and one ownership boundary at a time.
|
|
52
|
+
4. **Decision aid** — use a role table or comparison table only when it helps readers choose where something belongs.
|
|
53
|
+
5. **Tradeoffs** — state the learning cost, non-fit cases, and assumptions directly.
|
|
54
|
+
6. **Next step** — give readers a small experiment to try and a short list of authoritative further reading.
|
|
55
|
+
|
|
56
|
+
The article should answer both “what changes?” and “why should I care?” before adding advanced implementation detail.
|
|
57
|
+
|
|
58
|
+
When explaining architecture, prefer ownership questions over tool-name questions:
|
|
59
|
+
|
|
60
|
+
- Who owns this state or behavior?
|
|
61
|
+
- Who may depend on it?
|
|
62
|
+
- How long should it live?
|
|
63
|
+
- Which boundary owns caching, invalidation, persistence, or rendering?
|
|
64
|
+
|
|
65
|
+
This lets the article explain an architecture without becoming an API inventory.
|
|
66
|
+
|
|
67
|
+
## Explain Zova in its own model first
|
|
68
|
+
|
|
69
|
+
For Zova articles, begin with the controller / bean / IoC model before translating it into generic Vue terms. Vue comparisons are useful orientation aids, but they should not replace Zova's own concepts.
|
|
70
|
+
|
|
71
|
+
Keep these accuracy rules in view:
|
|
72
|
+
|
|
73
|
+
- Vue 3 provides Zova's reactive foundation.
|
|
74
|
+
- A controller field is not reactive merely because it is a TypeScript class field; it is reactive because Zova creates the controller as a framework-managed reactive bean.
|
|
75
|
+
- Controllers, beans, models, services, scopes, and TSX have distinct roles. Do not flatten them into synonyms for a composable or store.
|
|
76
|
+
- A Model is not simply “Zova's Pinia.” It can own query, mutation, cache, persistence, invalidation, and SSR-related state concerns.
|
|
77
|
+
- Discuss Cabloy Basic and Cabloy Start separately only when the UI layer, available suites, project assets, generated outputs, or edition-specific workflow affects the article.
|
|
78
|
+
|
|
79
|
+
For factual background, start from these guides:
|
|
80
|
+
|
|
81
|
+
- [Frontend Foundation](/frontend/foundation)
|
|
82
|
+
- [Reading Zova for Vue Developers](/frontend/reading-zova-for-vue-developers)
|
|
83
|
+
- [Zova vs Vue 3 Comparison](/frontend/zova-vs-vue3-comparison)
|
|
84
|
+
- [IoC and Beans](/frontend/ioc-and-beans)
|
|
85
|
+
- [Model Architecture](/frontend/model-architecture)
|
|
86
|
+
|
|
87
|
+
## Make examples earn their place
|
|
88
|
+
|
|
89
|
+
Use short examples that demonstrate one idea each. A helpful progression is:
|
|
90
|
+
|
|
91
|
+
1. page-local controller state and behavior;
|
|
92
|
+
2. a controller collaborating with an injected model or service;
|
|
93
|
+
3. an extraction that becomes justified as responsibility or reuse grows.
|
|
94
|
+
|
|
95
|
+
Every example should make the ownership boundary easier to see. If an example requires advanced lifecycle details, data contracts, or several framework concepts to understand, defer it or split it into smaller examples.
|
|
96
|
+
|
|
97
|
+
When a snippet has been simplified, say so. Do not present illustrative pseudocode as a copy-ready framework contract. Verify code, APIs, commands, and links against current sources before publishing.
|
|
98
|
+
|
|
99
|
+
Comparison tables should name the dimension being compared and describe a typical or default authoring model, not imply that every project in either ecosystem has identical structure.
|
|
100
|
+
|
|
101
|
+
## Keep the article balanced
|
|
102
|
+
|
|
103
|
+
Strong technical writing makes the boundary of its own recommendation clear.
|
|
104
|
+
|
|
105
|
+
Include the cost of the proposed approach. For example, a more structured controller/bean/model architecture may require authors to learn ownership, scope, and lifecycle rules; it may not be the most economical choice for a throwaway page or very small application.
|
|
106
|
+
|
|
107
|
+
Avoid framing flexible tools as defective. Explain the problem that emerges when complexity grows and the conditions under which a more explicit structure becomes valuable.
|
|
108
|
+
|
|
109
|
+
A practical article earns trust by telling readers both when to use an approach and when not to.
|
|
110
|
+
|
|
111
|
+
## Package articles consistently
|
|
112
|
+
|
|
113
|
+
Use a kebab-case topic directory under the local blog workspace:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
.assets/blogs/<topic-slug>/
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The canonical article should begin with frontmatter that makes its purpose and distribution metadata explicit. Use the fields relevant to the publishing target:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
title:
|
|
123
|
+
titleEn:
|
|
124
|
+
subtitle:
|
|
125
|
+
summary:
|
|
126
|
+
tags:
|
|
127
|
+
slug:
|
|
128
|
+
date:
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
When a bilingual release is in scope, create semantic sibling articles such as `article-zh.md` and `article-en.md`. Translate the thesis, caveats, examples, and linked evidence faithfully, but adapt titles, idioms, reader framing, and platform copy to the language rather than translating word-for-word.
|
|
132
|
+
|
|
133
|
+
When distribution is requested, keep publishing material separate from the canonical article. A publishing kit can contain:
|
|
134
|
+
|
|
135
|
+
- recommended and alternate titles;
|
|
136
|
+
- subtitle, short summary, long summary, and platform abstract;
|
|
137
|
+
- tags and selected cover;
|
|
138
|
+
- social or platform-specific copy;
|
|
139
|
+
- editorial and accuracy notes.
|
|
140
|
+
|
|
141
|
+
Treat cover copy and images as publishing deliverables, not evidence for technical claims. Use a readable 1600 × 900 cover when a social-preview image is needed.
|
|
142
|
+
|
|
143
|
+
## Pre-publication checklist
|
|
144
|
+
|
|
145
|
+
Before publishing, verify all of the following:
|
|
146
|
+
|
|
147
|
+
- [ ] The opening names a real reader problem and does not begin as framework promotion.
|
|
148
|
+
- [ ] The thesis is narrow, accurate, and non-adversarial.
|
|
149
|
+
- [ ] Each factual claim has current source or first-party documentation support.
|
|
150
|
+
- [ ] Interpretations and recommendations are written as interpretations and recommendations.
|
|
151
|
+
- [ ] Examples are concise, current, and explicit about simplification where applicable.
|
|
152
|
+
- [ ] Comparison tables describe dimensions and typical models, not universal truths.
|
|
153
|
+
- [ ] Tradeoffs and non-fit situations are stated plainly.
|
|
154
|
+
- [ ] Terminology, edition notes, commands, URLs, and documentation links are current.
|
|
155
|
+
- [ ] Bilingual siblings and publishing assets are aligned when they are part of the requested deliverable.
|
|
156
|
+
- [ ] Further reading directs readers to authoritative documentation, including [Verification](/ai/verification) when the article describes a development workflow.
|
|
157
|
+
|
|
158
|
+
The goal is not merely a polished argument. It is to leave the reader with a trustworthy mental model and a safe, concrete next step.
|