@jskit-ai/agent-docs 0.1.131 → 0.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.
Files changed (171) hide show
  1. package/guide/agent/app-extras/assistant.md +29 -605
  2. package/guide/agent/app-extras/mobile-capacitor.md +29 -362
  3. package/guide/agent/app-extras/realtime.md +29 -277
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +44 -815
  5. package/guide/agent/app-setup/authentication.md +43 -1073
  6. package/guide/agent/app-setup/console.md +26 -298
  7. package/guide/agent/app-setup/database-layer.md +110 -790
  8. package/guide/agent/app-setup/existing-application-migration.md +273 -0
  9. package/guide/agent/app-setup/initial-scaffolding.md +50 -784
  10. package/guide/agent/app-setup/multi-homing.md +39 -712
  11. package/guide/agent/app-setup/quickstart.md +43 -179
  12. package/guide/agent/app-setup/users.md +34 -353
  13. package/guide/agent/index.md +17 -23
  14. package/package.json +2 -2
  15. package/patterns/INDEX.md +7 -7
  16. package/patterns/child-cruds.md +3 -3
  17. package/patterns/client-requests.md +6 -6
  18. package/patterns/crud-authoring.md +94 -0
  19. package/patterns/crud-links.md +1 -1
  20. package/patterns/feature-package/PATTERN.md +108 -0
  21. package/patterns/feature-package/example/booking-engine/package.json +48 -0
  22. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
  23. package/patterns/feature-package/example/booking-engine/src/server/actions.js +26 -0
  24. package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
  25. package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
  26. package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
  27. package/patterns/feature-package/example/variations/customKnexRepository.js +34 -0
  28. package/patterns/feature-package/example/variations/orchestratorService.js +23 -0
  29. package/patterns/filters.md +8 -8
  30. package/patterns/live-actions.md +5 -18
  31. package/patterns/minimal-foundation/PATTERN.md +98 -0
  32. package/patterns/minimal-foundation/example/.nvmrc +1 -0
  33. package/patterns/minimal-foundation/example/AGENTS.md +17 -0
  34. package/patterns/minimal-foundation/example/Procfile +2 -0
  35. package/patterns/minimal-foundation/example/app.json +14 -0
  36. package/patterns/minimal-foundation/example/bin/develop.js +71 -0
  37. package/patterns/minimal-foundation/example/bin/server.js +8 -0
  38. package/patterns/minimal-foundation/example/config/public.js +40 -0
  39. package/patterns/minimal-foundation/example/config/server.js +1 -0
  40. package/patterns/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
  41. package/patterns/minimal-foundation/example/eslint.config.mjs +19 -0
  42. package/patterns/minimal-foundation/example/favicon.svg +7 -0
  43. package/patterns/minimal-foundation/example/gitignore +9 -0
  44. package/patterns/minimal-foundation/example/index.html +13 -0
  45. package/patterns/minimal-foundation/example/jsconfig.json +8 -0
  46. package/patterns/minimal-foundation/example/package.json +57 -0
  47. package/patterns/minimal-foundation/example/packages/main/package.json +42 -0
  48. package/patterns/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
  49. package/patterns/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  50. package/patterns/minimal-foundation/example/playwright.config.mjs +31 -0
  51. package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
  52. package/patterns/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
  53. package/patterns/minimal-foundation/example/server.js +195 -0
  54. package/patterns/minimal-foundation/example/src/App.vue +13 -0
  55. package/patterns/minimal-foundation/example/src/main.js +85 -0
  56. package/patterns/minimal-foundation/example/src/pages/home/index.vue +48 -0
  57. package/patterns/minimal-foundation/example/src/pages/home.vue +13 -0
  58. package/patterns/minimal-foundation/example/src/views/NotFound.vue +13 -0
  59. package/patterns/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
  60. package/patterns/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  61. package/patterns/minimal-foundation/example/tests/server/smoke.test.js +16 -0
  62. package/patterns/minimal-foundation/example/vite.config.mjs +81 -0
  63. package/patterns/page-scaffolding.md +20 -17
  64. package/patterns/placements.md +17 -15
  65. package/patterns/row-policies.md +4 -5
  66. package/patterns/server-search.md +3 -3
  67. package/patterns/shell-foundation/PATTERN.md +104 -0
  68. package/patterns/shell-foundation/example/.nvmrc +1 -0
  69. package/patterns/shell-foundation/example/AGENTS.md +17 -0
  70. package/patterns/shell-foundation/example/Procfile +2 -0
  71. package/patterns/shell-foundation/example/app.json +14 -0
  72. package/patterns/shell-foundation/example/bin/develop.js +71 -0
  73. package/patterns/shell-foundation/example/bin/server.js +8 -0
  74. package/patterns/shell-foundation/example/config/public.js +40 -0
  75. package/patterns/shell-foundation/example/config/server.js +1 -0
  76. package/patterns/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
  77. package/patterns/shell-foundation/example/eslint.config.mjs +19 -0
  78. package/patterns/shell-foundation/example/favicon.svg +7 -0
  79. package/patterns/shell-foundation/example/gitignore +9 -0
  80. package/patterns/shell-foundation/example/index.html +13 -0
  81. package/patterns/shell-foundation/example/jsconfig.json +8 -0
  82. package/patterns/shell-foundation/example/package.json +59 -0
  83. package/patterns/shell-foundation/example/packages/main/package.json +56 -0
  84. package/patterns/shell-foundation/example/packages/main/src/client/index.js +9 -0
  85. package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
  86. package/patterns/shell-foundation/example/packages/main/src/shared/index.js +10 -0
  87. package/patterns/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  88. package/patterns/shell-foundation/example/playwright.config.mjs +31 -0
  89. package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
  90. package/patterns/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
  91. package/patterns/shell-foundation/example/server.js +195 -0
  92. package/patterns/shell-foundation/example/src/App.vue +11 -0
  93. package/patterns/shell-foundation/example/src/components/ShellLayout.vue +12 -0
  94. package/patterns/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
  95. package/patterns/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
  96. package/patterns/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
  97. package/patterns/shell-foundation/example/src/error.js +19 -0
  98. package/patterns/shell-foundation/example/src/main.js +85 -0
  99. package/patterns/shell-foundation/example/src/pages/home/index.vue +116 -0
  100. package/patterns/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
  101. package/patterns/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
  102. package/patterns/shell-foundation/example/src/pages/home/settings.vue +109 -0
  103. package/patterns/shell-foundation/example/src/pages/home.vue +20 -0
  104. package/patterns/shell-foundation/example/src/placement.js +56 -0
  105. package/patterns/shell-foundation/example/src/placementTopology.js +149 -0
  106. package/patterns/shell-foundation/example/src/views/NotFound.vue +13 -0
  107. package/patterns/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
  108. package/patterns/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
  109. package/patterns/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  110. package/patterns/shell-foundation/example/tests/server/smoke.test.js +16 -0
  111. package/patterns/shell-foundation/example/vite.config.mjs +81 -0
  112. package/patterns/ui-contract.md +56 -0
  113. package/patterns/ui-testing.md +10 -12
  114. package/reference/autogen/KERNEL_MAP.md +29 -107
  115. package/reference/autogen/PATTERN_INDEX.md +230 -0
  116. package/reference/autogen/README.md +4 -8
  117. package/reference/autogen/packages/agent-docs.md +259 -0
  118. package/reference/autogen/packages/assistant-core.md +3 -3
  119. package/reference/autogen/packages/assistant-runtime.md +32 -17
  120. package/reference/autogen/packages/auth-core.md +31 -33
  121. package/reference/autogen/packages/auth-provider-local-core.md +4 -12
  122. package/reference/autogen/packages/auth-provider-local-db-core.md +4 -4
  123. package/reference/autogen/packages/auth-provider-supabase-core.md +14 -18
  124. package/reference/autogen/packages/auth-web.md +42 -22
  125. package/reference/autogen/packages/console-core.md +8 -25
  126. package/reference/autogen/packages/console-web.md +5 -5
  127. package/reference/autogen/packages/crud-core.md +61 -17
  128. package/reference/autogen/packages/database-runtime-mysql.md +12 -2
  129. package/reference/autogen/packages/database-runtime-postgres.md +12 -2
  130. package/reference/autogen/packages/database-runtime.md +26 -25
  131. package/reference/autogen/packages/google-rewarded-core.md +19 -104
  132. package/reference/autogen/packages/http-runtime.md +4 -8
  133. package/reference/autogen/packages/http-web.md +32 -0
  134. package/reference/autogen/packages/json-rest-api-core.md +4 -6
  135. package/reference/autogen/packages/kernel.md +109 -390
  136. package/reference/autogen/packages/mobile-capacitor.md +2 -13
  137. package/reference/autogen/packages/realtime.md +29 -26
  138. package/reference/autogen/packages/resource-crud-core.md +6 -0
  139. package/reference/autogen/packages/shell-web.md +69 -54
  140. package/reference/autogen/packages/storage-runtime.md +3 -3
  141. package/reference/autogen/packages/uploads-image-web.md +0 -1
  142. package/reference/autogen/packages/uploads-runtime.md +3 -3
  143. package/reference/autogen/packages/users-core.md +45 -90
  144. package/reference/autogen/packages/users-web.md +5 -7
  145. package/reference/autogen/packages/workspaces-core.md +53 -74
  146. package/reference/autogen/packages/workspaces-web.md +15 -16
  147. package/reference/autogen/tooling/jskit-catalog.md +34 -0
  148. package/reference/autogen/tooling/testUtils.md +4 -4
  149. package/skills/jskit/SKILL.md +38 -31
  150. package/skills/jskit/references/app-operations.md +68 -53
  151. package/skills/jskit/references/crud-operations.md +58 -106
  152. package/skills/jskit/references/material-3.md +1 -1
  153. package/skills/jskit/references/ui-operations.md +41 -44
  154. package/templates/app/AGENTS.md +7 -3
  155. package/guide/agent/app-setup/upgrade-beta-1-to-final.md +0 -252
  156. package/guide/agent/app-setup/working-with-the-jskit-cli.md +0 -325
  157. package/guide/agent/generators/advanced-cruds.md +0 -1935
  158. package/guide/agent/generators/crud-generators.md +0 -948
  159. package/guide/agent/generators/intro.md +0 -65
  160. package/guide/agent/generators/row-policies.md +0 -537
  161. package/guide/agent/generators/ui-generators.md +0 -690
  162. package/patterns/crud-scaffolding.md +0 -198
  163. package/patterns/generated-ui-contract-tracking.md +0 -66
  164. package/reference/autogen/packages/assistant.md +0 -68
  165. package/reference/autogen/packages/crud-server-generator.md +0 -215
  166. package/reference/autogen/packages/crud-ui-generator.md +0 -192
  167. package/reference/autogen/packages/feature-server-generator.md +0 -65
  168. package/reference/autogen/packages/ui-generator.md +0 -127
  169. package/reference/autogen/tooling/create-app.md +0 -317
  170. package/reference/autogen/tooling/jskit-cli.md +0 -933
  171. package/reference/autogen/tooling/test-support.md +0 -27
@@ -2,41 +2,35 @@
2
2
 
3
3
  # Guide
4
4
 
5
- This guide is the main hands-on path through JSKIT.
5
+ JSKIT is an AI-first framework and tested source-pattern library. It owns
6
+ strong runtime APIs, package composition contracts, and examples an agent can
7
+ apply or adapt. It does not prescribe an agent host or project orchestrator.
6
8
 
7
- It starts with a fast reproducible Quickstart, then steps back to the scaffold-first chapters that explain the default shell and runtime shape. After that, it introduces the database-backed users layer, expands into console and workspace-aware app structure, and adds a small `App extras` section for optional runtime packages such as the Android Capacitor shell, realtime, and assistant. Finally, the guide breaks out generator-specific workflows into their own section.
8
-
9
- ## Table of Contents
10
-
11
- ### App Setup
9
+ ## Start here
12
10
 
13
11
  - [Quickstart](/guide/app-setup/quickstart)
14
- - [Initial Scaffolding](/guide/app-setup/initial-scaffolding)
15
- - [Working With The JSKIT CLI](/guide/app-setup/working-with-the-jskit-cli)
16
- - [A More Interesting Shell](/guide/app-setup/a-more-interesting-shell)
12
+ - [Application foundations](/guide/app-setup/initial-scaffolding)
13
+ - [Migrate an existing application](/guide/app-setup/existing-application-migration)
14
+ - [A more interesting shell](/guide/app-setup/a-more-interesting-shell)
17
15
  - [Authentication](/guide/app-setup/authentication)
18
- - [Database Layer](/guide/app-setup/database-layer)
16
+ - [Database layer](/guide/app-setup/database-layer)
19
17
  - [Users](/guide/app-setup/users)
20
18
  - [Multi-homing](/guide/app-setup/multi-homing)
21
19
  - [Console](/guide/app-setup/console)
22
20
 
23
- ### App Extras
21
+ ## Optional capabilities
24
22
 
25
23
  - [Mobile Capacitor](/guide/app-extras/mobile-capacitor)
26
24
  - [Realtime](/guide/app-extras/realtime)
27
25
  - [Assistant](/guide/app-extras/assistant)
28
26
 
29
- ### Generators
30
-
31
- - [Intro](/guide/generators/intro)
32
- - [UI Generators](/guide/generators/ui-generators)
33
- - [CRUD Generators](/guide/generators/crud-generators)
34
- - [Advanced CRUDs](/guide/generators/advanced-cruds)
27
+ ## How to use the guide
35
28
 
36
- ## How to use this guide
29
+ Begin with the Quickstart and one application-foundation pattern. Add only the
30
+ capabilities selected by the product. For implementation, the installed JSKIT
31
+ skill routes the agent to package-owned `PATTERN.md` files and the smallest
32
+ relevant public API reference.
37
33
 
38
- - Start with `Quickstart` if you want the fastest route to a real workspace-enabled app and the first page-extension patterns.
39
- - Start with the rest of `App Setup` if you want to understand the base scaffold layer by layer.
40
- - Use `App Extras` once the base app structure is in place and you want optional runtime packages such as the Android shell, realtime, or assistant.
41
- - Jump into `Generators` if you already understand the runtime packages and want app-owned scaffolding workflows.
42
- - Inside `Generators`, read `CRUD Generators` before `Advanced CRUDs`: the first chapter teaches the workflow, and the second explains the generated anatomy and customization points.
34
+ There are no generator or CLI chapters. Their useful source examples are
35
+ package-owned patterns; their questionnaire, mutation, and provenance machinery
36
+ is not part of JSKIT.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.131",
3
+ "version": "0.1.133",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -11,7 +11,7 @@
11
11
  "templates"
12
12
  ],
13
13
  "scripts": {
14
- "test": "node --test"
14
+ "test": "node --test test/*.test.js"
15
15
  },
16
16
  "engines": {
17
17
  "node": "^22.13.0 || ^24.0.0 || ^26.0.0"
package/patterns/INDEX.md CHANGED
@@ -14,12 +14,12 @@ How to use it:
14
14
  - `placements.md`
15
15
  - surfaces, app/admin/home/console, "which surface", route ownership, placement visibility
16
16
  - `surfaces.md`
17
- - page, route page, placeholder page, screen stub, menu-linked page, `ui-generator page`, `list-placements`
17
+ - page, route page, placeholder page, screen stub, menu-linked page, placements
18
18
  - `page-scaffolding.md`
19
19
  - child crud, nested crud, embedded list, subroute, separate page, parent/child layout
20
20
  - `child-cruds.md`
21
- - crud scaffold, crud server, crud ui, table creation, migrations, direct knex, weird-custom persistence, fresh minimal app order, `crud-server-generator`, `crud-ui-generator`, `--delete-confirmation`
22
- - `crud-scaffolding.md`
21
+ - crud, crud server, crud ui, resource contract, table creation, migrations, ownership, JSON API, standard screens
22
+ - `crud-authoring.md`
23
23
  - CRUD links, record placeholders, `paths.page()`, `resolveViewUrl`, `resolveEditUrl`, `resolveParams`
24
24
  - `crud-links.md`
25
25
  - `definePage`, redirect, child redirect, settings landing, `redirectToChild`
@@ -30,8 +30,8 @@ How to use it:
30
30
  - `client-requests.md`
31
31
  - playwright, browser test, e2e, ui verification, baseline test, authenticated ui test, test auth, dev login as, dev auth bypass
32
32
  - `ui-testing.md`
33
- - generated UI contract, design contract, navigation roles, density, placeholder copy, card shells, shared CRUD screens, row actions, synthetic rows, detail slots
34
- - `generated-ui-contract-tracking.md`
33
+ - UI contract, design contract, navigation roles, density, placeholder copy, card shells, shared CRUD screens, row actions, synthetic rows, detail slots
34
+ - `ui-contract.md`
35
35
  - filter, filters, search facets, chips, date range, enum filter, lookup filter, `useCrudListFilters`, `createCrudListFilters`
36
36
  - `filters.md`
37
37
  - `searchSchema`, `search: true`, `applyFilter`, server search, query validators, backend filters, internal JSON REST filters
@@ -47,13 +47,13 @@ How to use it:
47
47
  - [surfaces.md](./surfaces.md)
48
48
  - [page-scaffolding.md](./page-scaffolding.md)
49
49
  - [child-cruds.md](./child-cruds.md)
50
- - [crud-scaffolding.md](./crud-scaffolding.md)
50
+ - [crud-authoring.md](./crud-authoring.md)
51
51
  - [crud-links.md](./crud-links.md)
52
52
  - [page-redirects.md](./page-redirects.md)
53
53
  - [live-actions.md](./live-actions.md)
54
54
  - [client-requests.md](./client-requests.md)
55
55
  - [ui-testing.md](./ui-testing.md)
56
- - [generated-ui-contract-tracking.md](./generated-ui-contract-tracking.md)
56
+ - [ui-contract.md](./ui-contract.md)
57
57
  - [filters.md](./filters.md)
58
58
  - [server-search.md](./server-search.md)
59
59
  - [crud-repository-mapping.md](./crud-repository-mapping.md)
@@ -8,7 +8,7 @@ Use when:
8
8
 
9
9
  Rules:
10
10
 
11
- - Before generating a child CRUD, ask how the user wants the child records laid out.
11
+ - Before authoring a child CRUD, ask how the user wants the child records laid out.
12
12
  - Do not assume one layout pattern by default.
13
13
 
14
14
  Clarify these options:
@@ -22,9 +22,9 @@ Clarify these options:
22
22
 
23
23
  Why this matters:
24
24
 
25
- - the answer changes route structure, placements, host containers, and which generator flow fits best
25
+ - the answer changes route structure, placements, host containers, and which source pattern fits best
26
26
  - child CRUD layout mistakes are expensive to unwind later
27
27
 
28
28
  Avoid:
29
29
 
30
- - generating nested CRUD routes before the parent/child layout is agreed
30
+ - authoring nested CRUD routes before the parent/child layout is agreed
@@ -19,7 +19,7 @@ Rules:
19
19
  Choose the function like this:
20
20
 
21
21
  ```js
22
- // 1. Generated CRUD route screen
22
+ // 1. Standard CRUD route screen
23
23
  const screen = useCrudListScreen({ ... });
24
24
 
25
25
  // 2. Button/toggle/small mutation
@@ -38,15 +38,15 @@ const form = useAddEdit({ ... });
38
38
  const resource = useEndpointResource({ ... });
39
39
  ```
40
40
 
41
- Use the shared CRUD screen wrappers when the route is a generated CRUD page:
41
+ Use the shared CRUD screen wrappers when the route is a standard CRUD page:
42
42
 
43
43
  - `useCrudListScreen()` plus `CrudListScreen` for list route pages
44
44
  - `useCrudViewScreen()` plus `CrudViewScreen` for record view route pages
45
- - `useCrudAddEditScreen()` plus `CrudAddEditScreen` for generated new/edit route pages
45
+ - `useCrudAddEditScreen()` plus `CrudAddEditScreen` for new/edit route pages
46
46
 
47
- Generated screen wrapper extension rules:
47
+ Screen wrapper extension rules:
48
48
 
49
- - Use `useCrudListScreen({ readEnabled })` for permission-gated generated list reads instead of splitting the page or replacing the shared list screen.
49
+ - Use `useCrudListScreen({ readEnabled })` for permission-gated list reads instead of splitting the page or replacing the shared list screen.
50
50
  - Use `useCrudListScreen({ requestQueryParams })` for list includes or other endpoint query params instead of putting query strings in `apiSuffix`.
51
51
  - Use `useCrudViewScreen({ requestQueryParams })` for detail includes instead of putting query strings in `apiUrlTemplate`.
52
52
  - Use `requestFieldsets` only when a specialised caller intentionally needs a typed JSON:API sparse fieldset. Ordinary generated reads use the complete resource output contract.
@@ -73,7 +73,7 @@ Why this is the standard JSKIT shape:
73
73
  - `httpWebClient` already handles credentials and CSRF behavior.
74
74
  - `useEndpointResource()` is the shared endpoint primitive for loading, saving, and standard load/save error handling. Higher-level runtimes add UI feedback and field-error handling on top.
75
75
  - Use `requestQueryParams` for endpoint query strings on list, view, and add/edit runtimes.
76
- - Generated CRUD and lookup reads use all resource-defined output fields by default. Hydrated relationships use the target resource's output contract. Generated pages and lookup controls do not repeat those definitions as request fieldsets.
76
+ - Standard CRUD and lookup reads use all resource-defined output fields by default. Hydrated relationships use the target resource's output contract. Pages and lookup controls do not repeat those definitions as request fieldsets.
77
77
  - Put exceptional large fields in `resource.contract.response.defaultExclude`. The target resource owns that default even when it is included by another resource.
78
78
  - `requestFieldsets` remains an explicit specialised override and accepts the canonical typed shape, for example `{ jobs: ["id", "status"], contacts: ["id", "displayName"] }`. It participates in both the request and the query cache key.
79
79
  - Sparse fieldsets are a serialization boundary, not an authorization mechanism. Server resources reject unknown fields, never serialize hidden fields, and preserve the fields needed internally for relationship linkage.
@@ -0,0 +1,94 @@
1
+ # CRUD authoring
2
+
3
+ Use this file for normal persisted entities, resource contracts, migrations,
4
+ JSON API routes, and matching screens.
5
+
6
+ ## Start from product decisions
7
+
8
+ Establish the entity, fields, relationships, ownership, access surface,
9
+ operations, search, sorting, and destructive behavior. Ask when a material
10
+ choice is missing. Do not turn these decisions into generator options.
11
+
12
+ Read these package-owned source patterns:
13
+
14
+ - `crud/resource-contract` for the shared field and ownership contract
15
+ - `crud/json-api-resource-package` for migration and server composition
16
+ - `crud/crud-screen-set` for routed list, view, create, edit, and delete UI
17
+
18
+ ## Normal implementation order
19
+
20
+ 1. Author a source-controlled migration in the package that owns the entity.
21
+ 2. Define the resource with `defineCrudResource()`.
22
+ 3. Bind standard server behavior with `defineCrudJsonApiFeature()`.
23
+ 4. Add only product-specific service methods, lifecycle, actions, validation,
24
+ policy, queries, messages, and orchestration.
25
+ 5. Declare the package provider and framework capabilities in `package.json`.
26
+ 6. Build thin route pages over JSKIT's shared CRUD screen APIs.
27
+ 7. Install the coherent package graph once.
28
+ 8. Rebuild a disposable database and run focused server, client, and browser
29
+ verification.
30
+
31
+ The migration and resource are both authored contracts. A live schema is useful
32
+ for understanding an imported system, but it is never the sole source of truth.
33
+
34
+ ## Ownership and access
35
+
36
+ - `public` means every record is intentionally public. It cannot be combined
37
+ with user or workspace ownership.
38
+ - `user` requires a real user ownership column and negative cross-user tests.
39
+ - `workspace` and `workspace_user` require an explicit workspace route/action
40
+ scope plus named permission policy.
41
+ - Domain relationships such as `recipient_user_id` are not ownership merely
42
+ because they point to a user.
43
+
44
+ Normal CRUD tables use one non-null single-column primary key. Foreign keys are
45
+ single-column and target compatible keys. Composite unique indexes may enforce
46
+ business rules but do not become framework identities.
47
+
48
+ ## Schema evolution
49
+
50
+ An unapplied migration may be edited normally. Once applied or released, add a
51
+ new immutable migration for the next change. Keep resource fields and storage
52
+ metadata aligned with the resulting schema. Do not use a field-patching command
53
+ or rewrite a historical baseline.
54
+
55
+ ## Customize without copying CRUD
56
+
57
+ `defineCrudJsonApiFeature()` deliberately keeps application extension points:
58
+
59
+ - `decorateRepository` adds the few persistence operations unique to the
60
+ resource.
61
+ - `decorateService` overrides standard methods or adds domain methods such as
62
+ `confirm`, `publish`, `cancel`, or `sendReminder`.
63
+ - `operationLifecycle` wraps a standard operation with `before`, `execute`,
64
+ `after`, and mutation-only `afterCommit` phases. Mutation phases before commit
65
+ receive the same transaction and `execute` receives `standard(nextInput)`.
66
+ - `actions` exposes non-CRUD service methods through normal validated,
67
+ permissioned, audited JSKIT actions and optional explicit HTTP routes.
68
+
69
+ Keep database reads and writes in repositories. Services and lifecycle hooks
70
+ orchestrate repositories; they do not issue raw database queries. Put external
71
+ side effects after commit, or write a durable outbox record inside the
72
+ transaction when delivery must be reliable.
73
+
74
+ ## When the resource abstraction does not fit
75
+
76
+ Use a separate explicit Feature for a different domain, aggregate, import job,
77
+ or command-oriented workflow that merely happens to mention the resource. A
78
+ CRUD resource may have many custom operations; it stops fitting only when CRUD
79
+ is no longer its principal public contract.
80
+
81
+ ## Verification
82
+
83
+ - rebuild from zero in a fresh disposable database
84
+ - validate accepted and rejected values at the resource boundary
85
+ - test list/view/create/update/delete document shapes
86
+ - test positive owner access and negative cross-owner access
87
+ - test relationships and deletion behavior
88
+ - verify skeletons, stable pending labels, toast mutation feedback, and no
89
+ horizontal overflow in compact, medium, and expanded screens
90
+ - run current framework and application verification
91
+
92
+ Avoid generator provenance, scaffold shapes, ownership receipts, workboards,
93
+ operation ledgers, hidden file markers, live-table-only schemas, and duplicated
94
+ route/request validators.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use when:
4
4
 
5
- - customizing generated CRUD pages
5
+ - customizing standard CRUD pages
6
6
  - wiring buttons or links on list/view/edit pages
7
7
  - building nested CRUD links
8
8
 
@@ -0,0 +1,108 @@
1
+ ---
2
+ id: server/feature-package
3
+ title: App-local server feature package
4
+ summary: Define a server feature through explicit capabilities and first-class actions, adding services or repositories only when its domain earns them.
5
+ keywords: actions, feature, json-rest, knex, orchestration, package, provider, repository, routes, server
6
+ requires: @jskit-ai/kernel
7
+ ---
8
+
9
+ # App-local server feature package
10
+
11
+ ## Use when
12
+
13
+ Use this pattern when a server capability has its own product language and
14
+ should not grow inside `packages/main`. It shows the smallest normal shape: a
15
+ feature declaration, named capability inputs and outputs, and first-class
16
+ actions whose implementations capture those exact dependencies.
17
+
18
+ The concrete `booking-engine` example is intentionally repository-free. The
19
+ `variations/` directory preserves the two important escalations: a meaningful
20
+ orchestration service and an explicit custom Knex repository for a domain that
21
+ cannot fit the normal resource APIs.
22
+
23
+ ## Do not use when
24
+
25
+ Do not create a package for a tiny composition callback or one route with no
26
+ domain behavior. Use the CRUD resource patterns when ordinary resource
27
+ operations fit. Do not select custom Knex merely because SQL is familiar; it
28
+ is an explicit exception for persistence behavior the higher-level APIs cannot
29
+ express.
30
+
31
+ ## Product decisions
32
+
33
+ Decide the feature's public operations, access surface, authentication policy,
34
+ input and output contracts, transactional boundary, and whether it truly owns
35
+ persistence. Decide whether HTTP routes are needed or another package will call
36
+ its actions internally. These decisions come from the product, not a JSKIT
37
+ questionnaire.
38
+
39
+ ## Invariants
40
+
41
+ - `packages/main` composes the application; substantial feature logic lives in
42
+ the feature package.
43
+ - `defineFeature()` receives only declared capabilities and returns only
44
+ declared feature APIs.
45
+ - Actions define the public operation contract and close over the feature APIs
46
+ they need. They never resolve arbitrary dependencies at execution time.
47
+ - The service orchestrates the feature and does not issue SQL directly.
48
+ - A repository owns persistence and accepts transaction/context options.
49
+ - The normal persistence lane uses a public or documented high-level resource
50
+ API; custom Knex is an explicit, reviewed exception.
51
+ - Ordinary HTTP and assistant exposure is projected from actions. Explicit
52
+ route code exists only for a genuinely custom transport.
53
+ - Register routes, actions, contributors, and other catalogue entries during
54
+ `setup()`. Runtime catalogues may be sealed before provider `boot()` begins.
55
+ Reserve `boot()` for starting long-lived work such as consumers, schedulers,
56
+ or notification loops after the application structure is complete.
57
+ - Application source contains no scaffold-shape, lane, provenance, receipt, or
58
+ authoring-history metadata.
59
+
60
+ ## Framework APIs
61
+
62
+ The provider uses `defineFeature()` from
63
+ `@jskit-ai/kernel/server/features`. The runtime supplies named capabilities
64
+ and the feature publishes its actions through the dedicated action catalogue.
65
+ The custom persistence variation uses `createWithTransaction()` from
66
+ `@jskit-ai/database-runtime/shared`.
67
+
68
+ ## Example files
69
+
70
+ `example/booking-engine/` is a concrete app-local package showing the preferred
71
+ small-feature boundary. Its status query is deliberately small: product logic
72
+ can grow inside the returned feature API without creating ceremonial layers.
73
+
74
+ `example/variations/AvailabilityEngineProvider.js` and
75
+ `example/variations/orchestratorService.js` show the repository-free lane.
76
+ `example/variations/InvoiceRollupProvider.js` and
77
+ `example/variations/customKnexRepository.js` show the explicit custom
78
+ persistence lane.
79
+
80
+ ## Variation points
81
+
82
+ Rename the package, capability id, actions, validators, and domain methods.
83
+ Select the correct channels and surfaces in `actionDefaults`, overriding them
84
+ only for exceptional actions. Add a service when orchestration is shared or
85
+ stateful. Add a repository only when the feature owns persistence. Replace the
86
+ illustrative status query with narrow product language before shipping.
87
+
88
+ ## Verification
89
+
90
+ - Import the feature and verify its declared capability inputs and outputs.
91
+ - Exercise actions through the action runtime, including invalid input and
92
+ denied access.
93
+ - Exercise HTTP routes only when the package owns them.
94
+ - Test service orchestration independently from persistence.
95
+ - Test repository transaction and context forwarding.
96
+ - Rebuild any schema from immutable migrations in a disposable database.
97
+ - Run the app's package, server, and integration verification.
98
+
99
+ ## Avoid
100
+
101
+ - product logic in the provider or `packages/main`
102
+ - registering routes or action catalogue entries from `boot()`
103
+ - direct SQL in actions, routes, or services
104
+ - a repository for an orchestration-only feature
105
+ - generic `execute(anything)` operations in finished product code
106
+ - `app.make()`, `scope.make()`, container tokens, or service-location helpers
107
+ - metadata claiming which authoring tool or pattern created the package
108
+ - field questionnaires, overwrite switches, or durable operation records
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@local/booking-engine",
3
+ "version": "0.1.0",
4
+ "description": "App-local booking orchestration package.",
5
+ "private": true,
6
+ "type": "module",
7
+ "dependencies": {
8
+ "@jskit-ai/kernel": "0.1.161",
9
+ "json-rest-schema": "^1.0.17"
10
+ },
11
+ "exports": {
12
+ "./server/actions": "./src/server/actions.js"
13
+ },
14
+ "jskit": {
15
+ "kind": "runtime",
16
+ "capabilities": {
17
+ "provides": [
18
+ "feature.booking-engine"
19
+ ],
20
+ "requires": [
21
+ "runtime.actions"
22
+ ]
23
+ },
24
+ "runtime": {
25
+ "server": {
26
+ "providers": [
27
+ {
28
+ "entrypoint": "src/server/BookingEngineProvider.js",
29
+ "export": "BookingEngineProvider"
30
+ }
31
+ ]
32
+ },
33
+ "client": {
34
+ "providers": []
35
+ }
36
+ },
37
+ "metadata": {
38
+ "apiSummary": {
39
+ "surfaces": [
40
+ {
41
+ "subpath": "./server/actions",
42
+ "summary": "Exports booking-engine action definitions."
43
+ }
44
+ ]
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,33 @@
1
+ import { defineFeature } from "@jskit-ai/kernel/server/features";
2
+ import { createActions } from "./actions.js";
3
+
4
+ const BookingEngineProvider = defineFeature({
5
+ id: "feature.booking-engine",
6
+ domain: "booking",
7
+ provides: {
8
+ bookingEngine: "feature.booking-engine"
9
+ },
10
+ actionDefaults: {
11
+ channels: ["api", "assistant", "internal"],
12
+ surfaces: ["app"]
13
+ },
14
+ setup() {
15
+ return {
16
+ bookingEngine: Object.freeze({
17
+ async readStatus(input = {}) {
18
+ return {
19
+ ok: true,
20
+ feature: "booking-engine",
21
+ scope: input.scope || "default",
22
+ verbose: input.verbose === true
23
+ };
24
+ }
25
+ })
26
+ };
27
+ },
28
+ actions({ bookingEngine }) {
29
+ return createActions({ bookingEngine });
30
+ }
31
+ });
32
+
33
+ export { BookingEngineProvider };
@@ -0,0 +1,26 @@
1
+ import { statusQueryInputValidator } from "./inputSchemas.js";
2
+
3
+ const ACTION_GET_STATUS = "feature.booking-engine.status.read";
4
+ function createActions({ bookingEngine } = {}) {
5
+ if (!bookingEngine || typeof bookingEngine.readStatus !== "function") {
6
+ throw new TypeError("createActions requires bookingEngine.readStatus().");
7
+ }
8
+
9
+ return Object.freeze([
10
+ {
11
+ id: ACTION_GET_STATUS,
12
+ version: 1,
13
+ kind: "query",
14
+ input: statusQueryInputValidator,
15
+ output: null,
16
+ idempotency: "none",
17
+ audit: { actionName: ACTION_GET_STATUS },
18
+ observability: {},
19
+ async execute(input) {
20
+ return bookingEngine.readStatus(input);
21
+ }
22
+ }
23
+ ]);
24
+ }
25
+
26
+ export { ACTION_GET_STATUS, createActions };
@@ -0,0 +1,19 @@
1
+ import { deepFreeze } from "@jskit-ai/kernel/shared/support/deepFreeze";
2
+ import { createSchema } from "json-rest-schema";
3
+
4
+ const statusQueryInputValidator = deepFreeze({
5
+ schema: createSchema({
6
+ scope: {
7
+ type: "string",
8
+ required: false,
9
+ minLength: 1
10
+ },
11
+ verbose: {
12
+ type: "boolean",
13
+ required: false
14
+ }
15
+ }),
16
+ mode: "patch"
17
+ });
18
+
19
+ export { statusQueryInputValidator };
@@ -0,0 +1,31 @@
1
+ import { defineFeature } from "@jskit-ai/kernel/server/features";
2
+ import { emptyInputValidator } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
3
+ import { createService } from "./orchestratorService.js";
4
+
5
+ const AvailabilityEngineProvider = defineFeature({
6
+ id: "feature.availability-engine",
7
+ domain: "availability",
8
+ provides: {
9
+ availabilityEngine: "feature.availability-engine"
10
+ },
11
+ actionDefaults: {
12
+ channels: ["api", "assistant", "internal"],
13
+ surfaces: ["app"]
14
+ },
15
+ setup() {
16
+ return { availabilityEngine: createService() };
17
+ },
18
+ actions({ availabilityEngine }) {
19
+ return [{
20
+ id: "availability.status.read",
21
+ kind: "query",
22
+ input: emptyInputValidator,
23
+ idempotency: "none",
24
+ async execute(input) {
25
+ return availabilityEngine.getStatus(input);
26
+ }
27
+ }];
28
+ }
29
+ });
30
+
31
+ export { AvailabilityEngineProvider };
@@ -0,0 +1,36 @@
1
+ import { defineFeature } from "@jskit-ai/kernel/server/features";
2
+ import { emptyInputValidator } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
3
+ import { createRepository } from "./repository.js";
4
+
5
+ const InvoiceRollupProvider = defineFeature({
6
+ id: "feature.invoice-rollup",
7
+ domain: "invoices",
8
+ requires: {
9
+ database: "runtime.database"
10
+ },
11
+ provides: {
12
+ invoiceRollup: "feature.invoice-rollup"
13
+ },
14
+ actionDefaults: {
15
+ channels: ["api", "assistant", "internal"],
16
+ surfaces: ["admin"]
17
+ },
18
+ setup({ database }) {
19
+ return {
20
+ invoiceRollup: createRepository({ knex: database.knex })
21
+ };
22
+ },
23
+ actions({ invoiceRollup }) {
24
+ return [{
25
+ id: "invoices.rollup.status.read",
26
+ kind: "query",
27
+ input: emptyInputValidator,
28
+ idempotency: "none",
29
+ async execute(input, context) {
30
+ return invoiceRollup.getStatus(input, { context });
31
+ }
32
+ }];
33
+ }
34
+ });
35
+
36
+ export { InvoiceRollupProvider };
@@ -0,0 +1,34 @@
1
+ import { createWithTransaction } from "@jskit-ai/database-runtime/shared";
2
+
3
+ function createRepository({ knex } = {}) {
4
+ if (!knex) {
5
+ throw new TypeError("createRepository requires knex.");
6
+ }
7
+
8
+ return Object.freeze({
9
+ withTransaction: createWithTransaction(knex),
10
+ async getStatus(input = {}, options = {}) {
11
+ return {
12
+ ok: true,
13
+ feature: "invoice-rollup",
14
+ persistence: "custom-knex",
15
+ tableName: "invoice_rollups",
16
+ hasTransaction: Boolean(options.trx),
17
+ input
18
+ };
19
+ },
20
+ async execute(input = {}, options = {}) {
21
+ return {
22
+ accepted: false,
23
+ feature: "invoice-rollup",
24
+ persistence: "custom-knex",
25
+ tableName: "invoice_rollups",
26
+ hasTransaction: Boolean(options.trx),
27
+ input,
28
+ message: "Replace this example with the reviewed domain-specific query."
29
+ };
30
+ }
31
+ });
32
+ }
33
+
34
+ export { createRepository };
@@ -0,0 +1,23 @@
1
+ function createService() {
2
+ return Object.freeze({
3
+ async getStatus(input = {}) {
4
+ return {
5
+ ok: true,
6
+ feature: "availability-engine",
7
+ mode: "orchestrator",
8
+ input
9
+ };
10
+ },
11
+ async execute(input = {}) {
12
+ return {
13
+ accepted: false,
14
+ feature: "availability-engine",
15
+ mode: "orchestrator",
16
+ input,
17
+ message: "Replace this example with calls to the feature's injected collaborators."
18
+ };
19
+ }
20
+ });
21
+ }
22
+
23
+ export { createService };