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.
Files changed (109) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-backend-scaffold/SKILL.md +1 -1
  3. package/.claude/skills/cabloy-backend-scaffold/evals/evals.json +6 -0
  4. package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +13 -4
  5. package/.claude/skills/cabloy-workflow/SKILL.md +4 -2
  6. package/.claude/skills/cabloy-workflow/evals/evals.json +14 -2
  7. package/.claude/skills/cabloy-worktree-environment/SKILL.md +206 -0
  8. package/.claude/skills/cabloy-worktree-environment/evals/evals.json +77 -0
  9. package/.github/workflows/vona-test-pg.yml +3 -0
  10. package/.github/workflows/vona-test-sqlite3.yml +3 -0
  11. package/CHANGELOG.md +21 -0
  12. package/CLAUDE.md +1 -1
  13. package/cabloy-docs/.vitepress/config.mjs +2 -0
  14. package/cabloy-docs/ai/playbook-technical-blog-authoring.md +158 -0
  15. package/cabloy-docs/backend/backend-contract-emission-specimen.md +2 -2
  16. package/cabloy-docs/backend/dto-guide.md +10 -7
  17. package/cabloy-docs/backend/dto-infer-generation.md +127 -7
  18. package/cabloy-docs/backend/foundation.md +1 -1
  19. package/cabloy-docs/backend/introduction.md +1 -0
  20. package/cabloy-docs/backend/module-dependencies.md +104 -0
  21. package/cabloy-docs/backend/serialization-guide.md +6 -0
  22. package/cabloy-docs/fullstack/parallel-worktree-environment.md +72 -34
  23. package/cabloy-docs/fullstack/suites-and-modules.md +1 -0
  24. package/cabloy-docs/reference/package-map.md +1 -0
  25. package/e2e/specs/a-commerce/commerce.spec.ts +89 -0
  26. package/package.json +2 -1
  27. package/scripts/init.ts +7 -12
  28. package/scripts/initAppName.test.ts +72 -0
  29. package/scripts/initAppName.ts +50 -0
  30. package/vona/packages-vona/vona/package.json +1 -1
  31. package/vona/pnpm-lock.yaml +48 -146
  32. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineCreate.tsx +6 -27
  33. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineItem.tsx +6 -31
  34. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineUpdate.tsx +6 -2
  35. package/vona/src/suite/a-commerce/modules/commerce-member/src/lib/addressMine.ts +16 -0
  36. package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +4 -17
  37. package/vona/src/suite/a-commerce/modules/commerce-member/test/addressOwnership.test.ts +63 -19
  38. package/vona/src/suite/a-commerce/modules/commerce-payment/package.json +2 -1
  39. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +11 -2
  40. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +26 -0
  41. package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +19 -2
  42. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/en-us.ts +5 -2
  43. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/zh-cn.ts +5 -2
  44. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateCreate.tsx +26 -35
  45. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateUpdate.tsx +6 -1
  46. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/entity/couponTemplate.tsx +40 -4
  47. package/vona/src/suite/a-commerce/modules/commerce-promotion/test/couponTemplateFormLayout.test.ts +85 -0
  48. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +1 -1
  49. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +3 -5
  50. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSummary.tsx +7 -40
  51. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/shipmentView.tsx +6 -15
  52. package/vona/src/suite/a-commerce/modules/commerce-trade/src/lib/order.ts +9 -0
  53. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +121 -11
  54. package/vona/src/suite/a-commerce/modules/commerce-trade/test/order.test.ts +25 -0
  55. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +19 -2
  56. package/vona/src/suite/a-training/modules/training-record/src/dto/detailRecordSubjectResItem.tsx +6 -1
  57. package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +3 -1
  58. package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +4 -1
  59. package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +45 -0
  60. package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordResItem.tsx +6 -1
  61. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +5 -23
  62. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +37 -5
  63. package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  64. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +29 -0
  65. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +3 -0
  66. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.redlock.ts +3 -1
  67. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +7 -0
  68. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/queue.outboxDispatch.ts +9 -4
  69. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +11 -0
  70. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/outboxEvent.tsx +11 -4
  71. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +12 -0
  72. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/webhookInbox.tsx +6 -0
  73. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/outbox.ts +12 -5
  74. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +1 -37
  75. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +355 -1
  76. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +226 -0
  77. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +148 -50
  78. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payScene.ts +2 -1
  79. package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
  80. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +39 -22
  81. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +42 -13
  82. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/controller/mockPayment.ts +11 -0
  83. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockRefundComplete.tsx +13 -0
  84. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockRefundReceipt.tsx +16 -0
  85. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +56 -0
  86. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +2 -1
  87. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +117 -8
  88. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
  89. package/vona/src/suite-vendor/a-pay/package.json +5 -5
  90. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  91. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoGet.ts +5 -5
  92. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  93. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +54 -12
  94. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +625 -64
  95. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/types.ts +55 -15
  96. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +1 -1
  97. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +15 -17
  98. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +12 -8
  99. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +111 -26
  100. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +3 -3
  101. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +1 -8
  102. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +5 -9
  103. package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +1 -1
  104. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +301 -17
  105. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +5461 -1788
  106. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/outbox.test.ts +0 -209
  107. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/paymentSession.test.ts +0 -153
  108. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/webhook.test.ts +0 -278
  109. 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.124
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 distinction, read [Backend Foundation](../../../cabloy-docs/backend/foundation.md#scope-lookup-vs-module-dependencies) and [Package Map](../../../cabloy-docs/reference/package-map.md).
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
- - target module is already composed into the application when code uses cross-module scope lookup
54
- - cross-module `this.$scope.<module>` or `app.scope(...)` lookup alone does not require `vonaModule.dependencies`
55
- - `vonaModule.dependencies` is added only for a genuine target-module availability, dependency-first ordering, or minimum-version requirement
56
- - do not create speculative dependency edges or circular declarations merely to document a lookup
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) for the canonical Cabloy Basic recipe.
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
- Before applying the broad `.env.local` recipe, check for more-specific `.env.*.local` overrides. Keep Vona and Zova `APP_NAME` values aligned, use the required matching API target, and add database, Redis, external-service, mock, or SSR-preview isolation only when the work actually uses those shared resources. For Cabloy Start, inspect the active Start repository rather than reusing the Basic recipe unchanged.
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. Checks for more-specific local overrides, uses Vona vona/env/.env.local with APP_NAME and SERVER_LISTEN_PORT, and Zova zova/env/.env.local with the same APP_NAME plus API_BASE_URL pointing to that Vona port, DEV_SERVER_PORT, and DEV_SERVER_HMR_PORT. Keeps SSR_API_BASE_URL inherited from API_BASE_URL unless a more-specific override changes it, and adds database, Redis, external-service, mock, or SSR-preview settings only when those resources are actually used.",
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.