cabloy 5.1.131 → 5.1.133
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-worktree-environment/SKILL.md +6 -6
- package/.claude/skills/cabloy-worktree-environment/evals/evals.json +2 -2
- package/.github/workflows/vona-test-pg.yml +1 -1
- package/.github/workflows/vona-test-sqlite3.yml +1 -1
- package/CHANGELOG.md +28 -0
- package/cabloy-docs/backend/dto-guide.md +39 -4
- package/cabloy-docs/backend/dto-infer-generation.md +29 -0
- package/cabloy-docs/backend/openapi-guide.md +16 -0
- package/cabloy-docs/backend/validation-guide.md +45 -0
- package/cabloy-docs/frontend/environment-config-guide.md +8 -15
- package/cabloy-docs/frontend/navigation-guards-guide.md +3 -3
- package/cabloy-docs/frontend/page-route-guide.md +4 -4
- package/cabloy-docs/frontend/ssr-env.md +22 -29
- package/cabloy-docs/frontend/theme-guide.md +4 -4
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +1 -1
- package/cabloy-docs/fullstack/deploy-cloudflare-docker.md +6 -6
- package/cabloy-docs/fullstack/parallel-worktree-environment.md +2 -2
- package/e2e/specs/a-commerce/commerce.spec.ts +479 -17
- package/e2e/specs/cabloy-basic/basic.spec.ts +30 -5
- package/package.json +7 -7
- package/vona/.claude/skills/detect-ssr-leak/SKILL.md +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +120 -10
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuCreate.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +13 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuUpdate.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuView.tsx +13 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/sku.tsx +6 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +227 -0
- package/vona/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +46 -36
- package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressSelectResItem.tsx +5 -13
- package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +16 -1
- package/vona/src/suite/a-commerce/modules/commerce-member/test/addressPresentation.test.ts +210 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +13 -2
- package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +12 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/service/coupon.ts +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +45 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +23 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +23 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +31 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineBase.tsx +56 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineResItem.tsx +17 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineView.tsx +13 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +26 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderView.tsx +197 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryAction.tsx +19 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryView.tsx +70 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditSelectResItem.tsx +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditView.tsx +21 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceSelectResItem.tsx +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceView.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/order.tsx +12 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +15 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +215 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockAudit.ts +25 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockBalance.ts +14 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +4 -4
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderPresentation.test.ts +358 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +8 -8
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +5 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +50 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockPresentation.test.ts +324 -0
- package/vona/src/suite/a-home/modules/home-base/package.json +3 -2
- package/vona/src/suite/a-home/modules/home-base/src/.metadata/index.ts +93 -16
- package/vona/src/suite/a-home/modules/home-base/src/controller/siteCatalog.ts +21 -0
- package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectRes.ts +11 -0
- package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectResItem.ts +15 -0
- package/vona/src/suite/a-home/modules/home-base/src/service/siteCatalog.ts +29 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +3 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +3 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +1 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/env.ts +1 -3
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +2 -1
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- 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 +67 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +1 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +5 -4
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +8 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +22 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +6 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +3 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperationRecoveryAudit.tsx +53 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +6 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperationRecoveryAudit.ts +12 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +6 -2
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +236 -30
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +8 -5
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +34 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +4 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +6 -0
- 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/bean/payProvider.mock.ts +15 -7
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +9 -5
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +289 -86
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/paypalGateway.ts +9 -1
- 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-openapi/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/src/types/rest.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/utils.ts +12 -0
- 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/dtoCreate.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoUpdate.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-validation/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-validation/src/bean/bean.validator.ts +60 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/lib/decorator/bean.ts +7 -4
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/types/dto.ts +2 -1
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/env/.env +3 -5
- package/zova/env/.env.cabloyBasicAdmin +1 -4
- package/zova/env/.env.cabloyBasicWeb +1 -5
- package/zova/env/.env.cabloyCommerce +1 -5
- package/zova/env/.env.cabloyCommerceAdmin +1 -4
- package/zova/env/.env.ssr.admin +1 -4
- package/zova/env/.env.ssr.web +1 -5
- package/zova/package.original.json +1 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +2 -1
- package/zova/packages-zova/zova-core/src/core/component/locale.ts +10 -4
- package/zova/packages-zova/zova-core/src/core/sys/config.ts +14 -6
- package/zova/packages-zova/zova-core/src/types/utils/env.ts +4 -2
- package/zova/pnpm-lock.yaml +24 -21
- package/zova/src/front/config/config/config.ts +22 -7
- package/zova/src/suite/a-commerce/modules/commerce-catalog/src/routes.ts +2 -2
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +16 -8
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +150 -216
- package/zova/src/suite/a-commerce/modules/commerce-member/src/model/addressMine.ts +1 -2
- package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-member/src/routes.ts +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-promotion/src/model/coupon.ts +1 -2
- package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/routes.ts +3 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +3 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +72 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +8 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +226 -16
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +15 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +155 -36
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +7 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +7 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/cart.ts +3 -4
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +42 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +2 -4
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +5 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +14 -10
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +151 -24
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +5 -5
- package/zova/src/suite/a-demo/modules/demo-basic/src/routes.ts +26 -7
- package/zova/src/suite/a-demo/modules/demo-todo/src/routes.ts +2 -2
- package/zova/src/suite/a-devui/modules/devui-adapter/src/bean/meta.themeHandler.ts +1 -1
- package/zova/src/suite/a-home/modules/home-base/package.json +1 -0
- package/zova/src/suite/a-home/modules/home-base/src/routes.ts +5 -0
- package/zova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts +1 -1
- package/zova/src/suite/a-home/modules/home-base/src/service/ssrLayout.ts +18 -14
- package/zova/src/suite/a-home/modules/home-indexadmin/src/routes.ts +1 -1
- package/zova/src/suite/a-home/modules/home-indexweb/src/routes.ts +1 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +12 -4
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts +8 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/model/layout.ts +5 -8
- package/zova/src/suite/a-home/modules/home-layoutempty/src/.metadata/index.ts +10 -3
- package/zova/src/suite/a-home/modules/home-layoutempty/src/component/layoutEmpty/controller.tsx +9 -3
- package/zova/src/suite/a-home/modules/home-layoutempty/src/config/config.ts +12 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +13 -8
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +1 -1
- package/zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts +4 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/model/layout.ts +5 -8
- package/zova/src/suite/a-home/modules/home-login/src/routes.ts +1 -0
- package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -3
- package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/routes.ts +3 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.ts +3 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +2 -2
- package/zova/src/suite-vendor/a-pay/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-interceptor/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.jwt.ts +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/config/config.ts +1 -17
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/bodyReadyObserver.ts +27 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/index.ts +2 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +33 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrMetaStore.ts +3 -35
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrProfile.ts +38 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/monkey.ts +10 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/config.ts +3 -10
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/ssr.ts +17 -8
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/src/service/ssrHandler.ts +33 -18
- package/zova/src/suite-vendor/a-zova/modules/a-style/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-style/src/bean/bean.theme.ts +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +7 -7
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.133
|
|
@@ -44,7 +44,7 @@ After validation, immediately generate the standard core tuple. Do not ask which
|
|
|
44
44
|
|
|
45
45
|
For user-facing summaries, write exactly:
|
|
46
46
|
|
|
47
|
-
>
|
|
47
|
+
> Environment isolation: Vona development + Zova development
|
|
48
48
|
|
|
49
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
50
|
|
|
@@ -52,11 +52,11 @@ Admin and Web use this same Zova environment. The user may later run either fron
|
|
|
52
52
|
|
|
53
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
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
|
|
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 **“Try another batch”** before setup or create another linked worktree; the actual application bind remains authoritative.
|
|
56
56
|
|
|
57
57
|
### Deterministic proposal
|
|
58
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
|
|
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 **“Try another batch”**.
|
|
60
60
|
|
|
61
61
|
Use one shared offset for every generated listener:
|
|
62
62
|
|
|
@@ -92,7 +92,7 @@ DEV_SERVER_HMR_PORT = <24679 + offset>
|
|
|
92
92
|
|
|
93
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
94
|
|
|
95
|
-
When the user says
|
|
95
|
+
When the user says **“Try another batch”**, 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
96
|
|
|
97
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
98
|
|
|
@@ -100,7 +100,7 @@ A unique `APP_NAME` separates ordinary framework-managed test database names and
|
|
|
100
100
|
|
|
101
101
|
Before making any edit:
|
|
102
102
|
|
|
103
|
-
1. show
|
|
103
|
+
1. show `Environment isolation: Vona development + Zova development`, the worktree ordinal, batch, and exact non-secret identity/port tuple
|
|
104
104
|
2. show a file-by-file preview containing only the managed assignments that will be written to both broad local files
|
|
105
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
106
|
4. recheck current root, linked-worktree identity, edition, ordinal, generated port range, tuple uniqueness, and both target states
|
|
@@ -199,7 +199,7 @@ git status --short
|
|
|
199
199
|
When this skill completes a stage, report:
|
|
200
200
|
|
|
201
201
|
1. validated worktree root and detected edition
|
|
202
|
-
2.
|
|
202
|
+
2. `Environment isolation: Vona development + Zova development`
|
|
203
203
|
3. worktree ordinal, batch, and generated non-secret identity/ports
|
|
204
204
|
4. both exact broad local files proposed or changed
|
|
205
205
|
5. the privacy boundary and external resources that still require separate isolation
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"id": 1,
|
|
6
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
|
|
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 Environment isolation: Vona development + Zova development, 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
8
|
"files": []
|
|
9
9
|
},
|
|
10
10
|
{
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
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.
|
|
48
|
+
"prompt": "I explicitly invoke /cabloy-worktree-environment in the first linked Cabloy Basic worktree. The initial proposal is 7103, 9001, and 24680. Try another batch.",
|
|
49
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
50
|
"files": []
|
|
51
51
|
},
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
- name: init
|
|
36
36
|
run: npm run init
|
|
37
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
|
|
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/paypalProvider.test.ts test-pay/test/paypalLifecycle.test.ts test-pay/test/outbox.test.ts test-pay/test/webhook.test.ts --flavor=normal
|
|
39
39
|
working-directory: vona
|
|
40
40
|
- name: run Commerce stock contention gate
|
|
41
41
|
run: |
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
- name: init
|
|
29
29
|
run: npm run init
|
|
30
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
|
|
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/paypalProvider.test.ts test-pay/test/paypalLifecycle.test.ts test-pay/test/outbox.test.ts test-pay/test/webhook.test.ts --flavor=normal
|
|
32
32
|
working-directory: vona
|
|
33
33
|
- name: run Commerce payment, shipment, and refund lifecycle gate
|
|
34
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
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.133
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add SSR profiles for core and commerce applications.
|
|
8
|
+
- Add payment UUIDs, refund support, and refunded-payment handling.
|
|
9
|
+
- Add administrative semantic presentations for addresses, orders, stock, and SKUs.
|
|
10
|
+
- Add payment capabilities and PayPal payment lifecycle coverage.
|
|
11
|
+
- Add SSR site title support and a home-page base.
|
|
12
|
+
- Preserve DTO OpenAPI schema scenarios.
|
|
13
|
+
- Add custom Zod error handling.
|
|
14
|
+
- Ensure passport availability for authenticated flows.
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
- Preserve SSR locale cookie typings.
|
|
19
|
+
- Harden PayPal refund recovery.
|
|
20
|
+
|
|
21
|
+
### Improvements
|
|
22
|
+
|
|
23
|
+
- Upgrade Lerna to v10.
|
|
24
|
+
|
|
25
|
+
## 5.1.132
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
- Update functionality.
|
|
30
|
+
|
|
3
31
|
## 5.1.131
|
|
4
32
|
|
|
5
33
|
### Features
|
|
@@ -73,11 +73,13 @@ class DtoStudentCreate {
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
When mixing helper metadata and
|
|
76
|
+
When mixing helper metadata and a structure-defining schema-like argument in `@Api.field(...)`, apply the same ordering rule used by entities:
|
|
77
77
|
|
|
78
|
-
- place `z.xxx(...)`
|
|
79
|
-
- keep helper metadata such as `v.xxx(...)` and `ZovaRender.xxx(...)` before
|
|
80
|
-
-
|
|
78
|
+
- place the final structure-defining argument, such as `z.xxx(...)`, `v.object(...)`, or `v.array(...)`, **last**
|
|
79
|
+
- keep helper metadata such as `v.xxx(...)` and `ZovaRender.xxx(...)` before it
|
|
80
|
+
- optionality, nullability, defaults, and preprocess/transform wrappers are also structure-shaping; do not assume their order is interchangeable
|
|
81
|
+
|
|
82
|
+
Framework DTO composition preserves inherited OpenAPI metadata, but that preservation does not make structure-shaping schema-like composition order-independent. Verify emitted schema/OpenAPI output after changing those arguments.
|
|
81
83
|
|
|
82
84
|
For query-oriented DTOs, another important distinction is optional vs nullable:
|
|
83
85
|
|
|
@@ -86,6 +88,39 @@ For query-oriented DTOs, another important distinction is optional vs nullable:
|
|
|
86
88
|
|
|
87
89
|
That becomes especially important for DTO query filters. A field declared with `v.optional(), v.nullable()` can preserve real `null` through query parsing so the downstream ORM filter can express SQL `IS NULL` instead of silently treating the value as omitted.
|
|
88
90
|
|
|
91
|
+
## DTO schema scenes
|
|
92
|
+
|
|
93
|
+
A DTO can declare the contract scene that its schema represents:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
@Dto({
|
|
97
|
+
schemaScene: 'filter',
|
|
98
|
+
fields: {
|
|
99
|
+
status: $makeSchema(v.optional(), z.string()),
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
export class DtoOrderFilter extends $Dto.query(EntityOrder, ['status']) {}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The shared scene vocabulary is:
|
|
106
|
+
|
|
107
|
+
- `table`
|
|
108
|
+
- `form`
|
|
109
|
+
- `form-view`
|
|
110
|
+
- `form-create`
|
|
111
|
+
- `filter`
|
|
112
|
+
|
|
113
|
+
`schemaScene` is emitted through Cabloy's `rest.schemaScene` OpenAPI extension metadata. It is not a standard OpenAPI field. The same metadata can therefore guide Vona request validation and Zova schema-driven consumers.
|
|
114
|
+
|
|
115
|
+
The inferred mutation helpers already declare the usual write intent:
|
|
116
|
+
|
|
117
|
+
- `$Dto.create(...)` uses `form-create`
|
|
118
|
+
- `$Dto.update(...)` uses `form`
|
|
119
|
+
|
|
120
|
+
Use `@Dto({ schemaScene })` when a named DTO has a deliberately different request-contract scene. Do not restate the normal create or update scene only because a DTO wraps one of those helpers.
|
|
121
|
+
|
|
122
|
+
Choose the scene from the API contract, not from the particular screen that happens to call it. A scene does not decide which fields the DTO contains: use `$Dto.*`, `columns`, `include`, and `dtoClass` to define the supported projection first. For the inferred authoring sequence, see [DTO Infer and Generation](/backend/dto-infer-generation); for scene-aware write handling, see [Validation Guide](/backend/validation-guide) and [OpenAPI Guide](/backend/openapi-guide).
|
|
123
|
+
|
|
89
124
|
## DTO options
|
|
90
125
|
|
|
91
126
|
Three especially important DTO option areas are:
|
|
@@ -191,6 +191,8 @@ export class DtoStudentSelectReq extends $Dto.queryPage(EntityStudent, [
|
|
|
191
191
|
|
|
192
192
|
`$makeSchema(...)` applies schema-like arguments right-to-left. Keep the final structure-defining schema, such as `z.string()`, `z.number()`, `v.object(...)`, or `v.array(...)`, last in authoring order. Treat optionality, nullability, defaults, preprocess/transform wrappers, objects, and arrays as structure-shaping rather than metadata-only, and verify emitted schema/OpenAPI output after changing them.
|
|
193
193
|
|
|
194
|
+
Framework DTO composition preserves inherited OpenAPI metadata when a field schema is refined. That includes metadata such as titles, render information, and scene identity. It does **not** make structure-shaping schema-like arguments order-independent: keep the final structure-defining argument last and verify the effective schema rather than assuming a metadata merge can repair a reordered schema.
|
|
195
|
+
|
|
194
196
|
`@Dto({ fields })` changes the runtime contract and metadata. It does not rewrite the TypeScript property type inferred from the `$Dto.*` base class. Do not add a duplicate `declare` field or a second field decorator solely to mirror a runtime schema restriction unless a separate static contract is genuinely required and is type-compatible with the inferred base.
|
|
195
197
|
|
|
196
198
|
### Layer 3: add contract-only fields
|
|
@@ -244,6 +246,33 @@ Representative source facts:
|
|
|
244
246
|
|
|
245
247
|
These are good examples of **named DTO classes that wrap inference**.
|
|
246
248
|
|
|
249
|
+
The mutation helpers also carry their conventional schema-scene identity into the DTO's Cabloy OpenAPI metadata:
|
|
250
|
+
|
|
251
|
+
| Helper | Effective schema scene | Practical effect |
|
|
252
|
+
| ------------------ | ---------------------- | ------------------------------------------------------------------- |
|
|
253
|
+
| `$Dto.create(...)` | `form-create` | Create-specific field metadata applies after the shared form layer. |
|
|
254
|
+
| `$Dto.update(...)` | `form` | Shared form field metadata applies directly. |
|
|
255
|
+
|
|
256
|
+
For `form-view`, `form-create`, and `filter`, field metadata resolves in this order: base `rest`, then the shared `rest.form` overlay, then the exact scene overlay. `table` has no shared-form overlay. For example, a field can remain read-only in normal form contracts while being enabled specifically for creation:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
@Dto({
|
|
260
|
+
fields: {
|
|
261
|
+
referenceNo: $makeMetadata(
|
|
262
|
+
v.openapi({
|
|
263
|
+
rest: {
|
|
264
|
+
'form': { readonly: true },
|
|
265
|
+
'form-create': { readonly: false },
|
|
266
|
+
},
|
|
267
|
+
}),
|
|
268
|
+
),
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
export class DtoOrderCreate extends $Dto.create(() => ModelOrder) {}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The effective `form-create` rule makes `referenceNo` writable for this create contract. An update DTO using the shared `form` scene keeps it read-only unless its own scene metadata changes that result. DTO options such as `fields`, `blocks`, `openapi`, and `schemaScene` merge with metadata supplied by inferred helpers or inheritance; they do not erase the helper-provided scene identity.
|
|
275
|
+
|
|
247
276
|
Why this is a good fit:
|
|
248
277
|
|
|
249
278
|
- the contracts are operation-specific and worth naming
|
|
@@ -60,6 +60,22 @@ That means:
|
|
|
60
60
|
|
|
61
61
|
This tight linkage is one of the reasons the Cabloy contract story can stay productive at scale.
|
|
62
62
|
|
|
63
|
+
## Schema scenes are Cabloy contract metadata
|
|
64
|
+
|
|
65
|
+
A DTO can emit its semantic schema scene through Cabloy's `rest.schemaScene` extension metadata. The scene vocabulary is `table`, `form`, `form-view`, `form-create`, and `filter`. This is Cabloy metadata carried by the emitted schema, not a field defined by the OpenAPI specification itself.
|
|
66
|
+
|
|
67
|
+
The same emitted metadata has coordinated but distinct consumers:
|
|
68
|
+
|
|
69
|
+
| Consumer | Responsibility |
|
|
70
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------- |
|
|
71
|
+
| Vona validation | Resolves a field's effective scene metadata and removes read-only properties from validated write input. |
|
|
72
|
+
| OpenAPI emission | Carries DTO and field scene metadata through the backend contract. |
|
|
73
|
+
| Zova schema/form runtime | Applies shared-form and exact-scene property overlays while loading fields for the active schema scene. |
|
|
74
|
+
|
|
75
|
+
For the form-derived scenes `form-view`, `form-create`, and `filter`, a field's base `rest` metadata is followed by the shared `rest.form` overlay and then the exact scene overlay. This lets one contract describe common form behavior while still declaring a create- or filter-specific exception.
|
|
76
|
+
|
|
77
|
+
The end-to-end rule is therefore not “the frontend hides a field.” Vona uses the DTO contract to sanitize read-only request input, while Zova uses compatible metadata to render the relevant scene. See [DTO Guide](/backend/dto-guide) for declaring a DTO scene, [Validation Guide](/backend/validation-guide) for server-side readonly handling, [OpenAPI Runtime Under the Hood](/frontend/a-openapi-under-the-hood) for Zova schema loading, and [Form Scene to Page Meta Guide](/frontend/form-scene-to-page-meta-guide) for frontend form-scene flow.
|
|
78
|
+
|
|
63
79
|
## Controllers, DTOs, entities, and examples all contribute
|
|
64
80
|
|
|
65
81
|
OpenAPI output is not owned by one layer only.
|
|
@@ -44,6 +44,49 @@ Inferred schemas can also be extended through helper tools like:
|
|
|
44
44
|
|
|
45
45
|
That is important because many real validation cases need augmentation rather than total replacement.
|
|
46
46
|
|
|
47
|
+
## Scene-aware readonly input sanitization
|
|
48
|
+
|
|
49
|
+
DTO and field OpenAPI metadata can identify a Cabloy schema scene and its scene-specific field behavior. After a schema parses successfully, Vona removes each known property whose **effective** `rest` metadata resolves to `readonly: true` for that scene.
|
|
50
|
+
|
|
51
|
+
This is server-side input sanitization, not a browser-only disabled control and not a validation error. A caller cannot turn a read-only field into a write channel by bypassing a Zova form.
|
|
52
|
+
|
|
53
|
+
For `form-view`, `form-create`, and `filter`, Vona resolves field metadata in this order:
|
|
54
|
+
|
|
55
|
+
1. base `rest` metadata
|
|
56
|
+
2. shared `rest.form` metadata
|
|
57
|
+
3. the exact scene metadata, such as `rest['form-create']`
|
|
58
|
+
|
|
59
|
+
For `table` and `form`, only the base metadata and exact-scene metadata apply. A nested DTO inherits the containing scene unless it declares its own `rest.schemaScene`.
|
|
60
|
+
|
|
61
|
+
The sanitization traverses nested DTO/object values and array elements, including framework lazy and chained schema composition. For example, a create request can prevent callers from supplying a line-item price while still accepting its quantity:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
class DtoLineItem {
|
|
65
|
+
@Api.field(v.openapi({ rest: { form: { readonly: true } } }))
|
|
66
|
+
price: number;
|
|
67
|
+
|
|
68
|
+
@Api.field()
|
|
69
|
+
quantity: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class DtoOrderCreate extends $Dto.create(() => ModelOrder) {
|
|
73
|
+
@Api.field(v.array(DtoLineItem))
|
|
74
|
+
items: DtoLineItem[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// request input
|
|
78
|
+
{
|
|
79
|
+
items: [{ price: 99, quantity: 2 }];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// validated value delivered to the handler
|
|
83
|
+
{
|
|
84
|
+
items: [{ quantity: 2 }];
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use DTO projection to omit a field that the API must never accept or return. Use scene-aware `readonly` when a field belongs to the schema but must be removed from write input for one contract scene. This sanitization is not response serialization; response payload shaping remains a separate concern in the [Serialization Guide](/backend/serialization-guide). General object parsing and unknown-key behavior still belong to the supplied Zod schema; readonly sanitization removes known protected fields only after successful parsing.
|
|
89
|
+
|
|
47
90
|
A useful distinction is:
|
|
48
91
|
|
|
49
92
|
- `v.optional` means the field may be omitted
|
|
@@ -82,6 +125,8 @@ When changing request contracts, ask:
|
|
|
82
125
|
2. does the contract need explicit extension through the `v` helpers?
|
|
83
126
|
3. does the same validation surface also feed OpenAPI and DTO behavior?
|
|
84
127
|
4. is the validation logic better expressed at the controller, DTO, or entity layer?
|
|
128
|
+
5. for a scene-aware DTO, what is its effective schema scene and does each protected field resolve to read-only there?
|
|
129
|
+
6. when protected fields can be nested, have object and array inputs been tested separately?
|
|
85
130
|
|
|
86
131
|
That produces more consistent backend contracts.
|
|
87
132
|
|
|
@@ -103,29 +103,22 @@ The config side follows the same merge pattern with `config.ts`, `config.[meta].
|
|
|
103
103
|
|
|
104
104
|
Different SSR flavors can intentionally expose different runtime capabilities rather than behaving identically.
|
|
105
105
|
|
|
106
|
-
A concrete example in the current Cabloy Basic frontend setup is SSR
|
|
106
|
+
A concrete example in the current Cabloy Basic frontend setup is the default SSR profile:
|
|
107
107
|
|
|
108
|
-
- Web
|
|
109
|
-
- Admin
|
|
108
|
+
- Web defaults to `SSR_PROFILE=public`
|
|
109
|
+
- Admin defaults to `SSR_PROFILE=session`
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
The effective profile is request-local: the active flavor's `SSR_PROFILE` supplies its default, and `route.meta.ssrProfile` can override it after route resolution. `public` keeps cookie-derived identity and theme state out of the server render; `session` permits normal cookie-backed Passport recovery and theme resolution, while forcing a private, non-storable response. Profiles define request-cookie capability, not a locale source: existing `route.meta.locale` controls URL-locale participation.
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
That means flavor selection is not only a packaging choice. It establishes the default capability boundary, while individual routes remain able to select the profile their rendering contract requires.
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
- Admin SSR can provide a stronger server/client theme match guarantee
|
|
115
|
+
Before assuming how SSR theme state is handed off and finalized, combine:
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
A second practical rule is that flavor alone is not the full story. Contributors should combine:
|
|
121
|
-
|
|
122
|
-
- flavor and `SSR_COOKIE` capability
|
|
117
|
+
- the effective SSR profile
|
|
123
118
|
- edition marker
|
|
124
119
|
- active UI-library adapter
|
|
125
120
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
For the theme-side contract and edition-aware checklist, see [Theme Guide](/frontend/theme-guide). For the env-side explanation of `SSR_COOKIE`, see [SSR Environment Variables](/frontend/ssr-env).
|
|
121
|
+
For the theme-side contract and edition-aware checklist, see [Theme Guide](/frontend/theme-guide). For the env-side explanation of `SSR_PROFILE`, see [SSR Environment Variables](/frontend/ssr-env).
|
|
129
122
|
|
|
130
123
|
## Scripts and runtime variants
|
|
131
124
|
|
|
@@ -25,7 +25,7 @@ class ServiceRouterGuards {
|
|
|
25
25
|
protected onRouterGuards(router: BeanRouter) {
|
|
26
26
|
router.beforeEach(async to => {
|
|
27
27
|
if (to.meta.requiresAuth === false) return;
|
|
28
|
-
if (
|
|
28
|
+
if (process.env.SERVER && this.$ssr.profile === 'public') return;
|
|
29
29
|
|
|
30
30
|
if (!this.$passport.isAuthenticated) {
|
|
31
31
|
const [_res, err] = await catchError(() => this.$passport.ensurePassport());
|
|
@@ -57,9 +57,9 @@ That means route configuration and guard behavior should be read together, not a
|
|
|
57
57
|
|
|
58
58
|
## SSR-sensitive detail
|
|
59
59
|
|
|
60
|
-
The example
|
|
60
|
+
The example uses the request-local `$ssr.profile` selected after route resolution and before the SSR app initializes.
|
|
61
61
|
|
|
62
|
-
When
|
|
62
|
+
When the effective profile is `public`, the server deliberately allows the protected route's neutral SSR entry. The browser restores Passport state and applies the same admission policy after hydration. A `session` profile permits the server to recover Passport and make the normal redirect or access-denied decision during the initial render. This preserves equivalent server and hydration-time initial rendering without weakening Client-side protection.
|
|
63
63
|
|
|
64
64
|
For cookie-enabled SSR, a rejected request must still use `$redirect(...)` so the SSR layer returns its HTTP redirect response. On the Client, return a route path or route-location object from the guard instead of using an imperative `$goto...()` helper.
|
|
65
65
|
|
|
@@ -59,10 +59,10 @@ The route meta surface includes important behavior such as:
|
|
|
59
59
|
- absolute-path behavior
|
|
60
60
|
- layout choice
|
|
61
61
|
- authentication requirement
|
|
62
|
-
- locale handling
|
|
62
|
+
- URL-locale handling through `meta.locale`
|
|
63
63
|
- component key behavior
|
|
64
64
|
- keepAlive behavior
|
|
65
|
-
- SSR
|
|
65
|
+
- SSR profile and nested `meta.ssrProfileOptions.responseCache` behavior
|
|
66
66
|
|
|
67
67
|
This is one reason route records matter so much: they are not just URL declarations. They are an application-behavior surface.
|
|
68
68
|
|
|
@@ -148,6 +148,6 @@ It should also check whether the route change affects:
|
|
|
148
148
|
- params typing
|
|
149
149
|
- auth behavior
|
|
150
150
|
- layout behavior
|
|
151
|
-
- locale behavior
|
|
152
|
-
- SSR behavior
|
|
151
|
+
- whether `meta.locale` should participate in URL-locale behavior
|
|
152
|
+
- SSR profile and nested `meta.ssrProfileOptions.responseCache` behavior
|
|
153
153
|
- metadata regeneration
|
|
@@ -12,54 +12,47 @@ Zova exposes SSR-related environment variables so the framework can configure ke
|
|
|
12
12
|
|
|
13
13
|
Representative variables include:
|
|
14
14
|
|
|
15
|
-
- `
|
|
15
|
+
- `SSR_PROFILE`
|
|
16
16
|
- `SSR_COOKIE_THEMEDARK_DEFAULT`
|
|
17
|
-
- `SSR_BODYREADYOBSERVER`
|
|
18
17
|
- `SSR_API_BASE_URL`
|
|
19
18
|
- `SSR_PROD_PORT`
|
|
20
|
-
- `SSR_TRANSFERCACHE`
|
|
21
|
-
- `SSR_TRANSFERCACHE_EXPIRES`
|
|
22
19
|
|
|
23
|
-
These affect
|
|
20
|
+
These affect SSR profile selection, theme defaults, server-side API targeting, and SSR production port behavior. Response-cache defaults are resolved from the selected request-local profile; body-ready behavior is an opt-in of the selected layout module, not an environment or profile switch.
|
|
24
21
|
|
|
25
|
-
## SSR
|
|
22
|
+
## SSR profile
|
|
26
23
|
|
|
27
|
-
`
|
|
24
|
+
`SSR_PROFILE` is the standalone-flavor default for request-local SSR behavior:
|
|
28
25
|
|
|
29
|
-
- `
|
|
30
|
-
-
|
|
31
|
-
- `SSR_TRANSFERCACHE_EXPIRES=0` emits `Cache-Control: no-cache, no-store, must-revalidate`.
|
|
32
|
-
- A positive number of seconds or an `ms`-style duration such as `10m` emits `Cache-Control: public, max-age=<seconds>`.
|
|
26
|
+
- `public`: the server renders without request-cookie credentials or cookie-backed theme resolution. Output must be anonymous-safe and may use public response caching.
|
|
27
|
+
- `session`: the server may recover request-cookie session state for normal route admission and authorized rendering. The response is always `Cache-Control: private, no-store`.
|
|
33
28
|
|
|
34
|
-
|
|
29
|
+
For Vona-backed SSR, `SSR_PROFILE` supplies the flavor default. After the frontend route is resolved, `route.meta.ssrProfile` can override that default before `serverEntry` runs. The resolved profile controls request-cookie capability and related SSR behavior; locale-aware URL handling remains the existing `route.meta.locale` contract. A profile never grants authentication, site admission, or API authorization; `requiresAuth` and Vona guards remain responsible for those decisions.
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
| ------ | --------------------------------------------------------- | ------------------------------------- |
|
|
38
|
-
| Web | `SSR_TRANSFERCACHE=true`, `SSR_TRANSFERCACHE_EXPIRES=10m` | `public, max-age=600` |
|
|
39
|
-
| Admin | `SSR_TRANSFERCACHE=true`, `SSR_TRANSFERCACHE_EXPIRES=0` | `no-cache, no-store, must-revalidate` |
|
|
31
|
+
The selected layout owns sidebar restoration. A layout that enables `layout.sidebar.bodyReadyObserver` queues a request-local hidden-body metadata entry during SSR, registers its readiness condition and restoration callback, and then injects the generic browser observer. The observer restores browser-local sidebar state after the relevant layout DOM exists and reveals the body before hydration. Admin enables this path; Web and Empty disable it. Therefore, a Web route using `ssrProfile: 'session'` remains `private, no-store` without gaining the Admin sidebar observer.
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
The selected layout also supplies its own desktop sidebar fallback and responsive breakpoint: the Admin layout defaults to open and the Web layout defaults to closed, and both currently use `1023px` as their independently configured breakpoint. Browser-local sidebar preference can override that fallback. The selected layout passes its breakpoint to the SSR browser handoff; it is not profile-specific. SSR profile selection does not change a layout's sidebar behavior.
|
|
42
34
|
|
|
43
|
-
##
|
|
35
|
+
## SSR response cache control
|
|
44
36
|
|
|
45
|
-
`
|
|
37
|
+
After Zova resolves the route profile, a `session` response immediately receives `Cache-Control: private, no-store`, before router guards or rendering can terminate it. A successfully rendered public route receives the profile default cache header, which `meta.ssrProfileOptions.responseCache` can refine.
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
Cabloy Basic uses different flavor defaults:
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
| Flavor | Default profile | SSR response header |
|
|
42
|
+
| ------ | --------------- | ------------------------------------ |
|
|
43
|
+
| Web | `public` | `public, max-age=600` when cacheable |
|
|
44
|
+
| Admin | `session` | `private, no-store` |
|
|
51
45
|
|
|
52
|
-
|
|
46
|
+
A route can override the flavor profile through `meta.ssrProfile` and can define a public response-cache policy through `meta.ssrProfileOptions.responseCache`. Set the nested value to `false` to disable public cache-header generation for that route. For Cloudflare cache-rule alignment that preserves these origin headers, see [Docker + Cloudflare Deployment](/fullstack/deploy-cloudflare-docker).
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
- In a cookie-disabled SSR path, SSR should treat theme-sensitive reads as non-authoritative for the browser's final theme and prefer hydration-tolerant or client-finalized decisions when exact matching matters.
|
|
48
|
+
## Theme implications of `SSR_PROFILE`
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
`SSR_PROFILE` determines whether the server can use cookie-backed theme state for the current request.
|
|
58
51
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
52
|
+
- `session`: the server can resolve theme state from request cookies during SSR.
|
|
53
|
+
- `public`: server theme reads are not authoritative for the browser's final theme. Keep theme-sensitive rendering hydration-tolerant and use the established browser-finalization path.
|
|
61
54
|
|
|
62
|
-
|
|
55
|
+
Use the active edition and UI library to determine the adapter-level implementation. Cabloy Basic and Cabloy Start share the profile contract but do not necessarily use the same SSR theme handoff.
|
|
63
56
|
|
|
64
57
|
For the broader theme usage contract and edition-aware checklist, see [Theme Guide](/frontend/theme-guide). For the runtime/flavor selection model behind these env choices, see [Environment and Config Guide](/frontend/environment-config-guide).
|
|
65
58
|
|
|
@@ -166,13 +166,13 @@ A practical split is:
|
|
|
166
166
|
- Web SSR is usually the lower-authority path for final browser theme when cookie-backed SSR resolution is unavailable
|
|
167
167
|
- Admin SSR is the stronger path for SSR-stable theme-sensitive rendering when cookie-backed SSR resolution is available
|
|
168
168
|
|
|
169
|
-
In practice,
|
|
169
|
+
In practice, check the request-local `$ssr.profile` and the active adapter behavior before assuming that server-rendered theme-sensitive output can exactly match the hydrated client state.
|
|
170
170
|
|
|
171
|
-
With `
|
|
171
|
+
With a `public` profile, server reads of `$theme.dark`, `$theme.darkMode`, and `$token` should be treated as non-authoritative for the browser's final theme unless the active adapter explicitly documents a stronger guarantee.
|
|
172
172
|
|
|
173
|
-
With `
|
|
173
|
+
With a `session` profile, SSR theme-sensitive branching can use cookie-backed state and rely on a stronger server/client match guarantee, but should still stay inside the established theme handler and hydration pipeline.
|
|
174
174
|
|
|
175
|
-
For the env-side explanation of `
|
|
175
|
+
For the env-side explanation of `SSR_PROFILE`, see [SSR Environment Variables](/frontend/ssr-env). For the flavor/runtime selection model, see [Environment and Config Guide](/frontend/environment-config-guide).
|
|
176
176
|
|
|
177
177
|
## Shared development rules
|
|
178
178
|
|
|
@@ -355,7 +355,7 @@ The framework service focuses on routing mechanics such as:
|
|
|
355
355
|
The `home-base` service focuses on application policy such as:
|
|
356
356
|
|
|
357
357
|
- auth enforcement through `meta.requiresAuth`
|
|
358
|
-
- locale initialization through `meta.locale`
|
|
358
|
+
- URL-locale participation and initialization through `meta.locale`
|
|
359
359
|
|
|
360
360
|
A practical reading takeaway is:
|
|
361
361
|
|
|
@@ -111,12 +111,12 @@ For current Cache Rule settings, see [Cache Rules settings](https://developers.c
|
|
|
111
111
|
|
|
112
112
|
## SSR cache contract
|
|
113
113
|
|
|
114
|
-
Zova SSR writes the cache contract during rendering
|
|
114
|
+
Zova SSR writes the public response-cache contract during rendering from the resolved profile and any public route-level `meta.ssrProfileOptions.responseCache` override. The effective SSR profile is authoritative: a `session` response always sets `Cache-Control: private, no-store` before route or profile response-cache policy is considered.
|
|
115
115
|
|
|
116
|
-
| Flavor | Default
|
|
117
|
-
| ------ |
|
|
118
|
-
| Web | `
|
|
119
|
-
| Admin | `
|
|
116
|
+
| Flavor | Default profile | SSR response header | Cloudflare result with this rule |
|
|
117
|
+
| ------ | --------------- | --------------------------------------------------- | --------------------------------------------------------------- |
|
|
118
|
+
| Web | `public` | `Cache-Control: public, max-age=600` when cacheable | Eligible to cache for ten minutes, subject to Cloudflare policy |
|
|
119
|
+
| Admin | `session` | `Cache-Control: private, no-store` | Not stored |
|
|
120
120
|
|
|
121
121
|
For Cabloy Start, verify the effective Web and Admin values in the licensed Start repository before creating the Cloudflare rule. The rule design remains the same: preserve and follow the origin `Cache-Control` response instead of replacing it.
|
|
122
122
|
|
|
@@ -132,5 +132,5 @@ After the origin is running, verify the following before relying on Cloudflare t
|
|
|
132
132
|
2. Each configured subdomain resolves to its expected enabled instance.
|
|
133
133
|
3. Nginx forwards the browser hostname instead of the literal value `localhost`.
|
|
134
134
|
4. Web SSR returns the `Cache-Control` header expected from the active edition and flavor configuration. In the current Basic baseline, it is `public, max-age=600`.
|
|
135
|
-
5. Admin SSR returns the `Cache-Control` header expected from the active edition and flavor configuration. In the current Basic baseline, it is `
|
|
135
|
+
5. Admin SSR returns the `Cache-Control` header expected from the active edition and flavor configuration. In the current Basic baseline, it is `private, no-store`.
|
|
136
136
|
6. After Cloudflare proxying is enabled, responses intended to be public-cacheable can be cached at the edge while responses marked `no-store` are not stored.
|
|
@@ -50,9 +50,9 @@ DEV_SERVER_HMR_PORT = 24680
|
|
|
50
50
|
|
|
51
51
|
The user-facing summary is:
|
|
52
52
|
|
|
53
|
-
>
|
|
53
|
+
> Environment isolation: Vona development + Zova development
|
|
54
54
|
|
|
55
|
-
If the proposal is unsuitable, say
|
|
55
|
+
If the proposal is unsuitable, say **“Try another batch”**. The skill increases every listener port by exactly `+1`, regenerates `API_BASE_URL` from the new Vona port, and presents the next tuple for confirmation. It never writes during this step.
|
|
56
56
|
|
|
57
57
|
This deterministic scheme is not a port reservation or a live collision check. If an application later reports that a port is occupied, request another batch before setup or create another linked worktree; successful application startup remains the final authority.
|
|
58
58
|
|