cabloy 5.1.157 → 5.1.159

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 (90) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-contract-loop/SKILL.md +24 -7
  3. package/.claude/skills/cabloy-contract-loop/evals/evals.json +12 -0
  4. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +28 -0
  5. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +19 -2
  6. package/.claude/skills/cabloy-resource-field-update/SKILL.md +18 -0
  7. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +14 -0
  8. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +10 -0
  9. package/.github/workflows/docs-pages.yml +18 -2
  10. package/CHANGELOG.md +26 -0
  11. package/CONTRIBUTING.md +84 -0
  12. package/LICENSES.md +5 -0
  13. package/package.json +2 -1
  14. package/repo-docs/.vitepress/config.mjs +34 -4
  15. package/repo-docs/.vitepress/theme/components/GitHubRepositoriesNav.vue +255 -0
  16. package/repo-docs/.vitepress/theme/custom.css +21 -0
  17. package/repo-docs/.vitepress/theme/index.js +7 -1
  18. package/repo-docs/backend/resource-field-update.md +48 -1
  19. package/repo-docs/blogs/index.md +2 -0
  20. package/repo-docs/frontend/form-layout-guide.md +6 -6
  21. package/repo-docs/frontend/page-guide.md +12 -0
  22. package/repo-docs/frontend/page-meta-guide.md +27 -0
  23. package/repo-docs/frontend/ssr-architecture-overview.md +4 -0
  24. package/repo-docs/frontend/ssr-build-deploy-guide.md +1 -1
  25. package/repo-docs/frontend/zova-form-source-reading-map.md +2 -2
  26. package/repo-docs/frontend/zova-form-under-the-hood.md +1 -1
  27. package/repo-docs/frontend/zova-reactivity-under-the-hood.md +65 -9
  28. package/repo-docs/fullstack/contract-loop-playbook.md +2 -0
  29. package/repo-docs/fullstack/ssr-site-and-flavor-setup.md +198 -0
  30. package/repo-docs/fullstack/vona-zova-integration.md +2 -0
  31. package/repo-e2e/docs/playwright.config.ts +37 -0
  32. package/repo-e2e/docs/specs/blogs-index.spec.ts +180 -0
  33. package/repo-e2e/docs/specs/github-repositories-nav.spec.ts +69 -0
  34. package/repo-e2e/docs/test-results/.last-run.json +4 -0
  35. package/repo-e2e/specs/cabloy-basic.spec.ts +136 -2
  36. package/vona/packages-cli/cli/package.json +1 -1
  37. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
  38. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
  39. package/vona/packages-cli/cli-set-api/package.json +1 -1
  40. package/vona/packages-vona/vona/package.json +1 -1
  41. package/vona/pnpm-lock.yaml +21 -80
  42. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/en-us.ts +3 -0
  43. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/zh-cn.ts +3 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productCreate.tsx +2 -0
  45. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productUpdate.tsx +2 -0
  46. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productView.tsx +2 -0
  47. package/vona/src/suite/a-training/modules/training-record/src/dto/recordCreate.tsx +1 -0
  48. package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectReq.tsx +3 -7
  49. package/vona/src/suite/a-training/modules/training-record/src/dto/recordUpdate.tsx +1 -0
  50. package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +1 -0
  51. package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +8 -0
  52. package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +51 -0
  53. package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +3 -0
  54. package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +3 -0
  55. package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +1 -0
  56. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +1 -0
  57. package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +1 -0
  58. package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +1 -0
  59. package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +10 -1
  60. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +99 -1
  61. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  62. package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
  63. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  64. package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
  65. package/vona/src/suite-vendor/a-vona/modules/a-web/src/bean/pipe.filter.ts +85 -57
  66. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  67. package/zova/packages-cli/cli/package.json +2 -2
  68. package/zova/packages-cli/cli-set-front/cli/templates/rest/render.ts +2 -0
  69. package/zova/packages-cli/cli-set-front/cli/templates/rest/rest.ts +13 -3
  70. package/zova/packages-cli/cli-set-front/package.json +1 -1
  71. package/zova/packages-zova/zova/package.json +2 -2
  72. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +31 -11
  73. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +3 -0
  74. package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +1 -1
  75. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +68 -8
  76. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  77. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +4 -0
  78. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  79. package/zova/src/suite-vendor/a-zova/modules/a-form/package.json +1 -1
  80. package/zova/src/suite-vendor/a-zova/modules/a-form/src/lib/formLayout.ts +0 -6
  81. package/zova/src/suite-vendor/a-zova/modules/a-form/test/lib/formLayout.test.ts +16 -9
  82. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  83. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +4 -0
  84. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +13 -2
  85. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/schema.ts +1 -0
  86. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  87. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +50 -0
  88. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx +60 -7
  89. package/zova/src/suite-vendor/a-zova/modules/a-table/src/types/table.ts +6 -4
  90. package/zova/src/suite-vendor/a-zova/package.json +4 -4
package/.cabloy-version CHANGED
@@ -1 +1 @@
1
- 5.1.157
1
+ 5.1.159
@@ -18,11 +18,11 @@ This includes the reverse fullstack direction where newly added frontend resourc
18
18
  In that situation:
19
19
 
20
20
  1. run the normal sync or regeneration flow first
21
- 2. run the relevant Zova build from the repo root before `npm run deps:vona`
22
- - use `npm run build:zova:admin` for Admin-facing render/action/metadata changes
23
- - also run `npm run build:zova:web` when the Web flavor is affected
21
+ 2. identify every affected flavor from the active repository’s root wrappers and lower-level Zova scripts, then run each matching paired SSR/REST build before `npm run deps:vona`
22
+ - `npm run build:zova:admin` and `npm run build:zova:web` are representative default wrappers only
23
+ - an independently named site must use its own source-confirmed paired root wrapper; do not relabel or assume a default wrapper refreshed it
24
24
  3. do not treat `build:rest:*` alone as sufficient, because the SSR bundle and rest output must move together
25
- 4. run `npm run deps:vona`
25
+ 4. run `npm run deps:vona` after the required flavor builds
26
26
  5. if the generated `.zova-rest` artifacts already contain the expected changes but Vona still sees stale types, delete `vona/node_modules` and reinstall dependencies
27
27
 
28
28
  Do not keep debugging source-level contract or renderer changes until the local file-package installation state is known to be healthy.
@@ -101,6 +101,22 @@ In this mode, first diagnose whether the visible stale behavior comes from skipp
101
101
 
102
102
  Use this mode when generated artifacts already contain the expected keys, types, or resources, but installed local file dependencies still behave stale after the normal sync flow.
103
103
 
104
+ ### Mode E: independent SSR flavor and site
105
+
106
+ Use this mode when the request adds a deployable Zova SSR surface that Vona must dispatch separately. This is more than a page or route inside an existing site.
107
+
108
+ Before proposing implementation, inspect the active repository rather than inferring names from Admin or Web:
109
+
110
+ 1. edition marker and root `package.json` wrappers;
111
+ 2. `zova/package.json` or its durable source for matching `dev:ssr:*`, `build:ssr:*`, and `build:rest:*` scripts;
112
+ 3. flavor env/config and its `SITE_ID`, mount path, SSR profile, and artifact-copy targets;
113
+ 4. a Vona `@SsrSite(...)` baseline and the owning site-module asset path;
114
+ 5. the expected SSR release directory and flavor-specific `zova-rest-*` package.
115
+
116
+ The independent identity tuple—flavor, site ID, public path, bundle path, REST package, Vona site module, and root paired-build wrapper—must be selected together. The root wrapper must build both SSR and REST output before `npm run deps:vona`; `build:rest:*` alone is not enough. Default Basic or Start Admin/Web wrappers are validated specimens, not a command template for a differently named site.
117
+
118
+ Read [Independent SSR Site and Flavor Setup](../../../repo-docs/fullstack/ssr-site-and-flavor-setup.md) for the canonical setup and evidence procedure.
119
+
104
120
  If the task is only backend scaffolding or only frontend scaffolding, the more specialized scaffold skills may be the better primary choice.
105
121
 
106
122
  ## Step 2: Start from the contract source of truth
@@ -225,7 +241,7 @@ Important Cabloy Basic reverse-sync rule:
225
241
  - if the change was consumer-side, low-confidence, cross-edition, or happened outside the Claude hook path, run the reverse sync flow deliberately yourself
226
242
  - prefer visible proof under `zova/src/**/.metadata/**` when it is available; if the effective handoff only appears in `.zova-rest`, treat the safeguard as conservative reminder/auto-sync assistance rather than strict proof
227
243
 
228
- For Cabloy Start, verify the exact Start-specific flavor names, paths, SSR site baselines, and project assets in the active Start repository.
244
+ For Cabloy Start, verify the exact Start-specific flavor names, paths, SSR site baselines, project assets, and source-confirmed root wrappers in the active Start repository. If the work affects an independent SSR site, follow Mode E: build that site’s paired wrapper rather than assuming an Admin/Web command covers it.
229
245
 
230
246
  ### Schema-driven UI decision branch
231
247
 
@@ -273,10 +289,11 @@ Especially verify:
273
289
 
274
290
  - active repo marker
275
291
  - affected frontend flavor
276
- - whether the change affects Admin, Web, or both
292
+ - whether the change affects a default Admin/Web site, an independent site, or more than one site
293
+ - source-confirmed root wrapper for every affected flavor
277
294
  - whether the generated output path is edition-specific
278
295
 
279
- Do not silently reuse Basic-specific examples in Start workflows.
296
+ Do not silently reuse Basic-specific examples in Start workflows or treat default Admin/Web commands as an independent-site template.
280
297
 
281
298
  ## Step 7: End-to-end verification
282
299
 
@@ -30,6 +30,18 @@
30
30
  "prompt": "One persisted Order domain needs read-only Admin select/view operations through presetResource and customer Web list/detail reads. Should Admin and Web share one API and ModelResource, or should I use mine/viewMine-style Web operations and a separate Web model? Include the Cabloy contract-loop steps.",
31
31
  "expected_output": "Keeps one domain and persistence boundary while separating Admin select/view and explicit owner-scoped Web operations with audience-specific DTOs. Keeps ModelResource as the Admin Resource owner and accepts a dedicated Web model/pages only for the distinct self-service state. Requires backend-first OpenAPI inspection, constrained regeneration for all owned operations, and verification of Admin authorization, Web owner scope before pagination, SSR admission where relevant, and both consumer paths. Rejects forcing Web through presetResource and rejects a parallel Admin cache owner for an ordinary custom Admin action.",
32
32
  "files": []
33
+ },
34
+ {
35
+ "id": 6,
36
+ "prompt": "In Cabloy Start, add an independently mounted SSR site with a new Zova flavor. What must be discovered and built before Vona can serve it?",
37
+ "expected_output": "Detects the Start repository and discovers the site-specific flavor env/config, lower-level SSR and REST scripts, root paired wrapper, Vona @SsrSite baseline, artifact path, and generated zova-rest package. Requires a new aligned site identity tuple and paired SSR-plus-REST build followed by deps:vona. Rejects reusing or relabeling default Admin/Web wrappers, REST-only rebuilding, and Commerce-specific names or paths as a generic template.",
38
+ "files": []
39
+ },
40
+ {
41
+ "id": 7,
42
+ "prompt": "A Vona consumer remains stale after an independent SSR flavor change. The new flavor artifacts appear correct. What is the safe Cabloy diagnosis order?",
43
+ "expected_output": "Requires proving that the selected site-specific wrapper generated both SSR and REST artifacts, confirming the matching Vona bundle/type identity, and running deps:vona before calling it local dependency drift. Does not suggest REST-only rebuilding or default Admin/Web commands for the independent site. Only after the normal handoff is proved does it recommend repairing Vona local installation state.",
44
+ "files": []
33
45
  }
34
46
  ]
35
47
  }
@@ -145,6 +145,34 @@ The Web model is valid only for the separate self-service state domain. It must
145
145
  - backend tooling and type hints
146
146
  - SSR or integration paths that depend on refreshed frontend output
147
147
 
148
+ ## Independent SSR site/flavor handoff map
149
+
150
+ Use this map when Vona must serve a newly independent Zova SSR site, rather than when a route is added to an existing site.
151
+
152
+ 1. authored site boundary
153
+ - flavor env and optional flavor config
154
+ - site-specific route, layout, admission, locale, and asset choices
155
+ - exact site ID and mounted public path
156
+ 2. paired frontend artifacts
157
+ - SSR bundle and client assets copied to the owning Vona site module
158
+ - flavor-specific generated REST/type package copied to Vona’s local workspace
159
+ - one source-confirmed root wrapper that produces both outputs
160
+ 3. Vona consumer registration
161
+ - independently packaged site module
162
+ - `@SsrSite(...)` identity, public path, bundle path, localized title, and diagnostics command
163
+ - typed site/public-path augmentation plus generated page/icon imports from the matching REST package
164
+ 4. dependency handoff
165
+ - run the selected site wrapper first
166
+ - run `npm run deps:vona` only after both artifacts exist
167
+ - do not treat `build:rest:*` alone as a Vona SSR handoff
168
+ 5. consumer proof
169
+ - Vona dispatch reaches the intended public path
170
+ - raw HTML is server-rendered and assets resolve
171
+ - browser hydration and route aliases preserve the mounted boundary
172
+ - admission, redirect, and cache behavior match the site contract
173
+
174
+ Default Admin/Web wrappers are specimens only. Discover the independently named site’s own scripts and generated paths from the active edition before recommending commands.
175
+
148
176
  ## Drift diagnosis matrix
149
177
 
150
178
  ### Source wrong
@@ -37,8 +37,9 @@ When one persisted domain has both Admin Resource and Web self-service consumers
37
37
 
38
38
  - frontend-owned source is correct
39
39
  - metadata generation completed when applicable
40
- - the relevant flavor build completed successfully
41
- - `deps:vona` completed
40
+ - every affected flavor’s source-confirmed paired SSR/REST build completed successfully
41
+ - `deps:vona` completed after the paired builds
42
+ - `build:rest:*` was not treated as the only Vona SSR handoff
42
43
  - backend consumers can resolve the refreshed frontend-generated handoff
43
44
  - prefer visible proof under `zova/src/**/.metadata/**` when it is available
44
45
  - this repo does not rely on a contract-loop pre-commit gate; the active safeguard is the Claude hook layer
@@ -48,6 +49,22 @@ When one persisted domain has both Admin Resource and Web self-service consumers
48
49
  - `npm run tsc:zova`
49
50
  - relevant flavor-specific or route-specific checks
50
51
 
52
+ ### Independent SSR site/flavor verification
53
+
54
+ When Vona consumes a new independent SSR site, also verify:
55
+
56
+ - the active edition and exact flavor are confirmed from source
57
+ - `SITE_ID`, Vona `siteId`, Zova `APP_PUBLIC_PATH`, and Vona `publicPath` align; enabled site IDs and public paths remain unique
58
+ - Vona `bundlePath` exactly matches the copied SSR release directory
59
+ - the generated `zova-rest-*` package matches the Vona type import
60
+ - the source-confirmed root wrapper generated both the SSR bundle and REST/type output
61
+ - `npm run deps:vona` ran after that paired build, and Vona resolves the refreshed local package
62
+ - the site diagnostics command names that same wrapper rather than a default Admin/Web command
63
+ - raw Vona-served HTML proves server rendering at the intended mounted path
64
+ - client assets load, hydration completes without mismatch, and aliases do not duplicate the mount path
65
+ - public/private admission, redirect, and cache expectations match the selected SSR profile
66
+ - targeted browser or E2E evidence covers the site through Vona, not only a standalone frontend server
67
+
51
68
  ## Consumer drift verification
52
69
 
53
70
  - source truth already looks correct
@@ -180,6 +180,24 @@ Important serialization reminder:
180
180
  - for performance reasons, Vona response serialization is opt-in per API action
181
181
  - verify that the target controller action explicitly uses `@Core.serializer()` before concluding that serializer metadata is broken
182
182
 
183
+ ### Join-backed foreign-key filtering and sorting
184
+
185
+ Use this metadata/query-contract branch when a persisted relation field remains an identity, but a resource list must filter or order it by a human-readable column on the related table. This is a metadata-only refinement when the foreign-key column already exists; do not increment `fileVersion` solely for this behavior.
186
+
187
+ Keep the entity field name and identity schema unchanged. Put the relation mapping on the entity field so inferred projections retain it:
188
+
189
+ - `v.filter({ table, joinType, joinOn, originalName, op })` maps the public relation field to the related display column;
190
+ - `ZovaRender.column({ enableSorting: true })` exposes the table sort control when the list should support ordering;
191
+ - preserve existing relation picker/cell metadata and `v.tableIdentity()` (or the applicable identity schema).
192
+
193
+ For a required relation, `innerJoin` is usually appropriate. When the relation is optional or unmatched base rows must remain visible, choose the join semantics explicitly instead of copying an inner-join example.
194
+
195
+ Keep the public query and order key equal to the foreign-key field name. In the select request DTO, retain that inferred field and use `$makeSchema(...)` only to change its query-input schema and renderer, usually to `v.optional()`, `z.string()`, and Cabloy Basic's `basic-input:formFieldInput`. Do not replace the entity storage schema with a string or add a parallel display-name parameter unless the API intentionally exposes separate ID and display-name filters.
196
+
197
+ Verify direct DTO metadata, the emitted optional text query parameter, absence of an unintended alternate parameter, visible sortable-column metadata, and endpoint filtering plus ascending/descending ordering. Confirm that filtering and ordering resolve to the intended related display column and inject the expected join.
198
+
199
+ See [Existing Resource Field Update](../../../repo-docs/backend/resource-field-update.md#filter-and-sort-a-relation-by-its-display-field) for the public pattern and links to the ORM and frontend query-flow guides.
200
+
183
201
  ## Step 6: Apply the renderer branch deliberately
184
202
 
185
203
  ### Default rule: prefer shared renderer reuse
@@ -139,6 +139,20 @@ When a translated schema title, renderer, or validation surface remains stale af
139
139
 
140
140
  The key distinction is between a genuinely stale generated contract and a valid schema facade captured from an earlier locale. `$computed` is only locale-safe when its dependency path reacquires the current schema source; wrapping an old facade or transformed snapshot does not make it current.
141
141
 
142
+ ### Raw-`this` reactivity boundary
143
+
144
+ When an author reports that a controller field changed but a TSX render, `$computed`, or `$watch` did not react, inspect this lifecycle boundary before recommending framework-neutral rewrites:
145
+
146
+ 1. inspect `zova-core/src/bean/beanContainer.ts` `BeanContainer._prepareBeanInstanceCommon(...)` to verify that `new BeanClass(...)` occurs before the framework exposes the reactive/proxied bean;
147
+ 2. inspect `BeanContainer._initBeanInstance(...)` to verify that `__init__()` is invoked only after preparation;
148
+ 3. check whether a class-field arrow callback or construction-time `bind(this)` captured raw `this` and later writes bean state;
149
+ 4. distinguish this from a callback created in `__init__()`, whose lexical `this` is the exposed bean; and
150
+ 5. verify whether the dependent render read through that same exposed identity.
151
+
152
+ State the consequence precisely: a proxy-based TSX render read can track normally, while a mutation through a raw construction-time callback changes the underlying field without notifying that dependency. An unrelated reactive update can later expose the changed value during another render.
153
+
154
+ Do **not** summarize this as “arrow functions are non-reactive,” and do not default to `ref.value`, `toRaw`, or generic Vue rewrites. Explain the Zova bean lifecycle first; recommend ordinary controller methods for normal actions, or closures created in `__init__()` only when a stable callback reference is required.
155
+
142
156
  ## Step 5: Explain Zova-native meaning first
143
157
 
144
158
  When answering, explain the Zova role first, then add Vue analogies only if they help.
@@ -20,6 +20,16 @@ Use when the question is about:
20
20
  - `$computed`
21
21
  - `$params` / `$query`
22
22
  - page render flow
23
+ - a class-field arrow callback, callback identity, or stale TSX after an apparent controller-state mutation
24
+
25
+ For a raw-`this` reactivity symptom, verify this expected sequence:
26
+
27
+ 1. `BeanContainer` constructs the class instance before it exposes the reactive/proxied bean;
28
+ 2. a class-field arrow callback captures that construction-time raw `this`;
29
+ 3. `__init__()` runs after preparation, so a closure created there captures the exposed bean instead; and
30
+ 4. a render dependency invalidates only when its mutation travels through the same exposed reactive identity used for the read.
31
+
32
+ Therefore, do not classify the issue as “arrow functions are non-reactive.” Distinguish a raw-captured write that changes the underlying field without a trigger from an ordinary controller method or `__init__()` callback that writes through the exposed bean.
23
33
 
24
34
  ## Component controller and wrapper path
25
35
 
@@ -5,6 +5,9 @@ on:
5
5
  - main
6
6
  paths:
7
7
  - 'repo-docs/**'
8
+ - 'repo-e2e/docs/**'
9
+ - 'package.json'
10
+ - 'pnpm-lock.yaml'
8
11
  - 'README.md'
9
12
  - '.github/workflows/docs-pages.yml'
10
13
  workflow_dispatch:
@@ -33,12 +36,25 @@ jobs:
33
36
  node-version: 24
34
37
  cache: pnpm
35
38
  cache-dependency-path: repo-docs/pnpm-lock.yaml
39
+ - name: install root dependencies
40
+ run: pnpm install --frozen-lockfile
36
41
  - name: install docs dependencies
37
42
  run: pnpm --dir repo-docs install --frozen-lockfile
38
- - name: build docs
43
+ - name: install Chromium
44
+ run: pnpm exec playwright install --with-deps chromium
45
+ - name: build docs and verify layout
39
46
  env:
40
47
  GA_MEASUREMENT_ID: ${{ vars.GA_MEASUREMENT_ID }}
41
- run: pnpm --dir repo-docs docs:build
48
+ run: npm run test:docs:e2e
49
+ - name: upload docs E2E artifacts
50
+ if: failure()
51
+ uses: actions/upload-artifact@v7
52
+ with:
53
+ name: docs-e2e-artifacts
54
+ path: |
55
+ repo-e2e/docs/playwright-report/
56
+ repo-e2e/docs/test-results/
57
+ if-no-files-found: ignore
42
58
  - name: setup pages
43
59
  uses: actions/configure-pages@v5
44
60
  - name: upload pages artifact
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.159
4
+
5
+ ### Features
6
+
7
+ - Add form layout support.
8
+ - Add render column support.
9
+ - Add OpenAPI title support for DTOs.
10
+ - Add form schema title support.
11
+ - Add configurable page title keys.
12
+ - Add blog styling enhancements.
13
+
14
+ ### Improvements
15
+
16
+ - Update documentation for joined backend filtering and sorting.
17
+ - Document raw `this` reactivity boundaries.
18
+ - Document SSR site and flavor setup.
19
+ - Improve documentation links, layouts, page metadata guidance, and blog styling.
20
+ - Update site configuration and controller behavior.
21
+
22
+ ## 5.1.158
23
+
24
+ ### Improvements
25
+
26
+ - Add licensing documentation.
27
+ - Add contribution guidelines.
28
+
3
29
  ## 5.1.157
4
30
 
5
31
  ### Features
@@ -0,0 +1,84 @@
1
+ # Contributing to Cabloy Basic
2
+
3
+ Contributions to Cabloy Basic source, tests, tooling, and documentation are welcome. Cabloy Basic is the public Cabloy framework/reference edition, with Vona backend and Zova frontend layers.
4
+
5
+ ## Before you begin
6
+
7
+ - Use [GitHub Issues](https://github.com/cabloy/cabloy/issues) for reproducible bugs, public questions, and feature proposals. Search for an existing issue first.
8
+ - Use [pull requests](https://github.com/cabloy/cabloy/pulls) for focused, reviewable changes.
9
+ - For a bug report, include the expected and actual behavior, a minimal reproduction or sufficient setup details, and relevant Cabloy, Node.js, pnpm, database, and browser/runtime versions.
10
+ - Remove credentials, tokens, personal data, and sensitive system information from issues, logs, screenshots, and pull requests.
11
+
12
+ ## Set up a development checkout
13
+
14
+ You need Git, Node.js `>=24.4.0`, pnpm `>=11.5.2`, Redis `>=7.2.6`, and one documented development database baseline: SQLite, MySQL `>=8`, or PostgreSQL `>=16`. SQLite setups using `better-sqlite3` may also require a native build toolchain for `node-gyp`.
15
+
16
+ ```bash
17
+ git clone https://github.com/cabloy/cabloy.git
18
+ cd cabloy
19
+ npm run init
20
+ ```
21
+
22
+ `npm run init` is more than a package install: it installs multiple workspaces, prepares generated local configuration, initializes and synchronizes Vona and Zova, and generates required frontend and backend artifacts. Run it intentionally rather than as a retry for an unrelated narrow change.
23
+
24
+ Current CI workflows run on Ubuntu with Node.js 24 after pushes to `main`; do not assume that every pull request is automatically validated. For maintained onboarding guidance, see [Cabloy Basic](https://cabloy.com/editions/cabloy-basic).
25
+
26
+ ## Develop and validate
27
+
28
+ Start with the narrowest meaningful check, then broaden validation when a change crosses a shared boundary.
29
+
30
+ | Purpose | Command |
31
+ | ---------------------------------------- | -------------------------- |
32
+ | Start Vona development | `npm run dev` |
33
+ | Start one Vona development process | `npm run dev:one` |
34
+ | Start Basic Admin SSR development | `npm run dev:zova:admin` |
35
+ | Start Basic Web SSR development | `npm run dev:zova:web` |
36
+ | Check formatting | `npm run format` |
37
+ | Lint | `npm run lint` |
38
+ | Type-check Vona and Zova | `npm run tsc` |
39
+ | Run backend tests | `npm run test` |
40
+ | Run the full E2E suite | `npm run test:e2e` |
41
+ | Rerun E2E tests without reset | `npm run test:e2e:fast` |
42
+ | Build required Basic artifacts | `npm run build` |
43
+ | Build Basic Admin SSR and REST artifacts | `npm run build:zova:admin` |
44
+ | Build Basic Web SSR and REST artifacts | `npm run build:zova:web` |
45
+ | Synchronize Zova dependencies into Vona | `npm run deps:vona` |
46
+ | Build the public documentation site | `npm run docs:build` |
47
+
48
+ The tracked pre-commit hook runs `lint-staged`. It may format staged Markdown and configuration files, and may lint-fix and format staged source files. Review the resulting staged changes and run the relevant explicit checks before submitting.
49
+
50
+ ## Generated code and Vona–Zova integration
51
+
52
+ Use Vona backend contracts, DTOs, OpenAPI metadata, and schema metadata as contract truth. Regenerate consumers rather than hand-editing generated frontend artifacts.
53
+
54
+ For frontend metadata or dependency changes that Vona consumes, build every affected Basic flavor before synchronizing dependencies:
55
+
56
+ ```bash
57
+ npm run build:zova:admin
58
+ # Also run npm run build:zova:web when Web is affected.
59
+ npm run deps:vona
60
+ ```
61
+
62
+ Keep SSR and REST outputs aligned; a REST-only build is not sufficient. See the canonical [Contract Loop Playbook](https://cabloy.com/fullstack/contract-loop-playbook), [Vona + Zova Integration](https://cabloy.com/fullstack/vona-zova-integration), and [repository scripts reference](https://cabloy.com/reference/repo-scripts).
63
+
64
+ ## Pull requests
65
+
66
+ Keep each pull request focused and describe its user-visible and technical effects. Include:
67
+
68
+ - the related issue when one exists;
69
+ - tests added or updated for behavioral changes;
70
+ - the exact validation commands run and their results;
71
+ - any regenerated contract artifacts and the build/synchronization steps used; and
72
+ - documentation updates, or why no documentation update is needed.
73
+
74
+ Do not include unrelated generated output, build artifacts, environment files, credentials, or cache files.
75
+
76
+ ## Documentation
77
+
78
+ Canonical public Cabloy documentation is maintained in this repository's `repo-docs/` tree and published at [cabloy.com](https://cabloy.com). Discuss and submit proposed public-documentation changes in an issue or pull request; do not treat copies outside this repository as independent canonical sources.
79
+
80
+ ## License and contribution rights
81
+
82
+ Cabloy Basic project-owned content is licensed under the root [MIT License](./LICENSE).
83
+
84
+ Submit only material that you have the right to contribute. Preserve required copyright, license, attribution, and third-party notices for any included code, media, fonts, generated material, or copied snippets.
package/LICENSES.md ADDED
@@ -0,0 +1,5 @@
1
+ # License Scope
2
+
3
+ Unless a file or directory includes its own complete license or third-party notice, Cabloy Basic project-owned source, documentation, and assets inherit the root [MIT License](./LICENSE).
4
+
5
+ Third-party material remains subject to the license and notice provided with that material or otherwise required by its upstream terms.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.157",
3
+ "version": "5.1.159",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -47,6 +47,7 @@
47
47
  "test": "cd vona && npm run test",
48
48
  "test:e2e": "node repo-e2e/scripts/runE2e.ts --clean",
49
49
  "test:e2e:fast": "node repo-e2e/scripts/runE2e.ts --fast",
50
+ "test:docs:e2e": "npm run docs:build && playwright test --config repo-e2e/docs/playwright.config.ts",
50
51
  "db:reset": "cd vona && npm run db:reset",
51
52
  "tsc": "npm run tsc:zova && pnpm --dir vona run tsc",
52
53
  "tsc:zova": "pnpm --dir zova run tsc",
@@ -97,6 +97,7 @@ const fullstackGroups = [
97
97
  },
98
98
  { text: 'Framework Performance', link: '/fullstack/framework-performance' },
99
99
  { text: 'Vona + Zova Integration', link: '/fullstack/vona-zova-integration' },
100
+ { text: 'SSR Site and Flavor Setup', link: '/fullstack/ssr-site-and-flavor-setup' },
100
101
  { text: 'A-Pay Payment Suite', link: '/fullstack/a-pay-payment-suite' },
101
102
  {
102
103
  text: 'Payment Provider Sandbox Configuration',
@@ -191,19 +192,49 @@ export default defineConfig({
191
192
  base: '/',
192
193
  ignoreDeadLinks: [/^https?:\/\/localhost/],
193
194
  head: gaHead,
195
+ transformPageData(pageData) {
196
+ if (!/^blogs\/[^/]+\/index\.md$/.test(pageData.relativePath)) return;
197
+
198
+ const pageClass = [pageData.frontmatter.pageClass, 'cabloy-blogs-article']
199
+ .filter(Boolean)
200
+ .join(' ');
201
+ return {
202
+ frontmatter: {
203
+ ...pageData.frontmatter,
204
+ pageClass,
205
+ },
206
+ };
207
+ },
194
208
  markdown: {
195
209
  lineNumbers: true,
196
210
  },
197
211
  themeConfig: {
198
212
  nav: [
199
213
  { text: 'Home', link: '/' },
214
+ {
215
+ text: 'Docs',
216
+ items: [
217
+ { text: 'Fullstack', link: '/fullstack/introduction', activeMatch: '^/fullstack/' },
218
+ { text: 'Backend (Vona)', link: '/backend/introduction', activeMatch: '^/backend/' },
219
+ { text: 'Frontend (Zova)', link: '/frontend/introduction', activeMatch: '^/frontend/' },
220
+ ],
221
+ },
200
222
  { text: 'Blogs', link: '/blogs/', activeMatch: '^/blogs/' },
201
- { text: 'Fullstack', link: '/fullstack/introduction', activeMatch: '^/fullstack/' },
202
- { text: 'Backend (Vona)', link: '/backend/introduction', activeMatch: '^/backend/' },
203
- { text: 'Frontend (Zova)', link: '/frontend/introduction', activeMatch: '^/frontend/' },
204
223
  { text: 'Editions', link: '/editions/overview', activeMatch: '^/editions/' },
205
224
  { text: 'AI Development', link: '/ai/introduction', activeMatch: '^/ai/' },
206
225
  { text: 'Reference', link: '/reference/introduction', activeMatch: '^/reference/' },
226
+ {
227
+ component: 'GitHubRepositoriesNav',
228
+ props: {
229
+ repositories: [
230
+ { text: 'github.com/cabloy/cabloy', link: 'https://github.com/cabloy/cabloy' },
231
+ {
232
+ text: 'github.com/cabloy/cabloy-start',
233
+ link: 'https://github.com/cabloy/cabloy-start',
234
+ },
235
+ ],
236
+ },
237
+ },
207
238
  ],
208
239
  sidebar: {
209
240
  '/fullstack/': fullstackGroups,
@@ -634,7 +665,6 @@ export default defineConfig({
634
665
  ],
635
666
  '/reference/': referenceGroups,
636
667
  },
637
- socialLinks: [{ icon: 'github', link: 'https://github.com/cabloy/cabloy' }],
638
668
  search: {
639
669
  provider: 'local',
640
670
  },