@jskit-ai/agent-docs 0.1.114 → 0.1.116
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/guide/agent/app-setup/a-more-interesting-shell.md +17 -0
- package/guide/agent/app-setup/initial-scaffolding.md +15 -2
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +14 -0
- package/guide/agent/generators/crud-generators.md +83 -1
- package/guide/agent/index.md +3 -0
- package/package.json +1 -1
- package/patterns/INDEX.md +4 -4
- package/patterns/crud-repository-mapping.md +5 -0
- package/patterns/crud-scaffolding.md +43 -0
- package/patterns/generated-ui-contract-tracking.md +1 -1
- package/patterns/live-actions.md +21 -0
- package/patterns/ui-testing.md +13 -1
- package/reference/autogen/packages/crud-core.md +1 -1
- package/reference/autogen/packages/crud-ui-generator.md +6 -0
- package/reference/autogen/packages/database-runtime.md +12 -0
- package/reference/autogen/packages/json-rest-api-core.md +3 -2
- package/reference/autogen/packages/shell-web.md +8 -0
- package/reference/autogen/packages/users-core.md +0 -3
- package/reference/autogen/packages/users-web.md +12 -1
- package/reference/autogen/packages/workspaces-core.md +0 -3
- package/skills/jskit/SKILL.md +25 -58
- package/skills/jskit/references/app-operations.md +51 -25
- package/skills/jskit/references/crud-operations.md +75 -67
- package/skills/jskit/references/ui-operations.md +41 -47
|
@@ -671,6 +671,23 @@ import {
|
|
|
671
671
|
- whether the drawer is open right now
|
|
672
672
|
- whether the drawer should open by default on load
|
|
673
673
|
|
|
674
|
+
The closed presentation is adaptive and uses Vuetify's Material navigation
|
|
675
|
+
components. On compact/mobile layouts the temporary drawer closes completely.
|
|
676
|
+
On medium and expanded layouts it collapses to a navigation rail by default,
|
|
677
|
+
so primary navigation remains visible. Opening it restores the full drawer.
|
|
678
|
+
|
|
679
|
+
The app-owned `ShellLayout` can opt into a fully hidden wide drawer when the
|
|
680
|
+
product has another discoverable navigation affordance:
|
|
681
|
+
|
|
682
|
+
```vue
|
|
683
|
+
<ShellLayout desktop-drawer-closed-mode="hidden">
|
|
684
|
+
<RouterView />
|
|
685
|
+
</ShellLayout>
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
The default is `desktop-drawer-closed-mode="rail"`. Prefer that Material 3
|
|
689
|
+
pattern; do not imitate a rail with custom CSS or a second menu registry.
|
|
690
|
+
|
|
674
691
|
`useShellErrorPresentationStore()` exposes the current banner, snackbar, and dialog presentation state behind `ShellErrorHost`.
|
|
675
692
|
|
|
676
693
|
The simplest direct store usage looks like this:
|
|
@@ -38,7 +38,18 @@ If you deliberately need the older bare scaffold, use `--minimal` or `--template
|
|
|
38
38
|
npx @jskit-ai/create-app exampleapp --minimal --tenancy-mode none
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Minimal apps can still install the standard shell later with
|
|
41
|
+
Minimal apps can still install the standard shell later with
|
|
42
|
+
`npx --no-install jskit add package shell-web`, as long as the starter files it
|
|
43
|
+
claims have not been edited first. After the initial `npm install`, prefer
|
|
44
|
+
`npx --no-install jskit` for every local JSKIT command so a missing local CLI
|
|
45
|
+
fails clearly.
|
|
46
|
+
|
|
47
|
+
When a minimal app's first feature is generated CRUD, do not pre-install the
|
|
48
|
+
shell as a workaround. Add the database runtime, run `npm install`, create the
|
|
49
|
+
live disposable table, run `crud-server-generator scaffold`, run
|
|
50
|
+
`npm install` again, and then run `crud-ui-generator crud`. The server
|
|
51
|
+
generator installs the shell/realtime dependency closure in the correct order.
|
|
52
|
+
The complete Notes command lane is in [CRUD Generators](/guide/generators/crud-generators#fresh-minimal-notes-app-the-complete-command-order).
|
|
42
53
|
|
|
43
54
|
If you already know you want a small non-workspace baseline right after the scaffold, this is the shortest reproducible path:
|
|
44
55
|
|
|
@@ -184,7 +195,7 @@ The most important parts look like this:
|
|
|
184
195
|
"@tanstack/vue-query": "^5.101.0",
|
|
185
196
|
"@jskit-ai/http-runtime": "0.x",
|
|
186
197
|
"fastify": "^5.8.5",
|
|
187
|
-
"json-rest-schema": "^1.0.
|
|
198
|
+
"json-rest-schema": "^1.0.17",
|
|
188
199
|
"pinia": "^3.0.4",
|
|
189
200
|
"vue": "^3.5.38",
|
|
190
201
|
"vue-router": "^5.1.0",
|
|
@@ -211,6 +222,8 @@ That matters because JSKIT maintenance policy changes over time. If the scaffold
|
|
|
211
222
|
|
|
212
223
|
The Playwright scaffold follows the same rule. `playwright.config.mjs` delegates to `@jskit-ai/jskit-cli/test/playwright`, and the starter browser specs delegate their shared responsive checks to published JSKIT helpers. The generated files stay small while later JSKIT package updates can change local server startup, managed `PLAYWRIGHT_BASE_URL` handling, and `VIBE64_PLAYWRIGHT_STORAGE_STATE` support without copying that logic into each new app.
|
|
213
224
|
|
|
225
|
+
The scaffold also configures `src/typed-router.d.ts` as generated output. It is intentionally absent from a fresh scaffold and ignored by Git; the Vue Router Vite plugin writes it during the first `npm run dev` or `npm run build` route scan.
|
|
226
|
+
|
|
214
227
|
`jskit app verify` is worth noticing specifically. Linting, tests, and builds check your source code and runtime behavior. The JSKIT part of that flow runs `doctor`, which checks JSKIT-managed app state: installed package visibility, lock-file-backed managed files, and other JSKIT-specific health rules. It is there because a JSKIT app is not only code. It is also a descriptor-driven managed project.
|
|
215
228
|
|
|
216
229
|
The starter scaffold also writes `.github/workflows/jskit-verify.yml`. JSKIT generates and owns that workflow as a projection of installed package `ci` contracts. The baseline runs checkout, Node 26 setup, `npm ci`, and `npm run verify`. Packages can add job environment values, service containers, and explicit `before-verify` steps without taking ownership of the whole YAML file. For example, the database runtime adds migrations before verification. Its MySQL driver adds a MariaDB service with synthetic CI-only credentials and `DB_CLIENT=mysql2`; its Postgres driver adds the equivalent Postgres service and `DB_CLIENT=pg`.
|
|
@@ -45,6 +45,20 @@ That lock file is the source of truth for installed JSKIT-managed package state.
|
|
|
45
45
|
|
|
46
46
|
That is why commands such as `update`, `remove`, `position`, `migrations`, and `doctor` all care about `.jskit/lock.json`.
|
|
47
47
|
|
|
48
|
+
### App-owned does not mean disposable
|
|
49
|
+
|
|
50
|
+
A path recorded in `.jskit/lock.json` remains managed while its owning package
|
|
51
|
+
is installed. “App-owned” means customizable, not disposable while the package
|
|
52
|
+
remains installed. You may edit the file; you may not delete or rename it
|
|
53
|
+
without changing the managed package contract.
|
|
54
|
+
|
|
55
|
+
Never delete or rename a recorded managed path. Adapt generated infrastructure
|
|
56
|
+
tests in place. If a starter product route is replaced, update the scaffold
|
|
57
|
+
smoke test to exercise the new canonical route instead of deleting baseline
|
|
58
|
+
browser coverage. In particular, preserve managed tests such as
|
|
59
|
+
`tests/e2e/base-shell.spec.ts` and `tests/e2e/adaptive-shell.spec.ts`. Doctor
|
|
60
|
+
must continue to flag a managed test that is missing.
|
|
61
|
+
|
|
48
62
|
## JSKIT-managed app maintenance scripts
|
|
49
63
|
|
|
50
64
|
The scaffolded app also has a small set of `npm run` shortcuts that are really wrappers around JSKIT-owned maintenance behavior.
|
|
@@ -31,6 +31,73 @@ It is meant to answer:
|
|
|
31
31
|
|
|
32
32
|
Once that workflow is clear, continue with [Advanced CRUDs](/guide/generators/advanced-cruds) for the generated package anatomy, ownership model, and customization boundaries.
|
|
33
33
|
|
|
34
|
+
## Fresh minimal Notes app: the complete command order
|
|
35
|
+
|
|
36
|
+
The dependency install boundaries are part of the workflow. After the first
|
|
37
|
+
install, use `npx --no-install jskit` so the command fails if the app-local CLI
|
|
38
|
+
is unavailable instead of fetching a different copy.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx @jskit-ai/create-app notes \
|
|
42
|
+
--target . \
|
|
43
|
+
--force \
|
|
44
|
+
--tenancy-mode none \
|
|
45
|
+
--minimal
|
|
46
|
+
npm install
|
|
47
|
+
|
|
48
|
+
npx --no-install jskit add package database-runtime-mysql
|
|
49
|
+
npm install
|
|
50
|
+
|
|
51
|
+
# Create and select a fresh disposable database, then create the live `notes` table.
|
|
52
|
+
|
|
53
|
+
npx --no-install jskit generate crud-server-generator scaffold \
|
|
54
|
+
--namespace notes \
|
|
55
|
+
--surface home \
|
|
56
|
+
--ownership-filter public \
|
|
57
|
+
--access public \
|
|
58
|
+
--table-name notes
|
|
59
|
+
npm install
|
|
60
|
+
|
|
61
|
+
npx --no-install jskit generate crud-ui-generator crud notes \
|
|
62
|
+
--resource-file packages/notes/src/shared/noteResource.js \
|
|
63
|
+
--id-param noteId \
|
|
64
|
+
--display-fields title,body \
|
|
65
|
+
--parent-title contextual \
|
|
66
|
+
--navigation-role primary \
|
|
67
|
+
--delete-confirmation
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The server generator resolves the complete package closure. `shell-web`
|
|
71
|
+
establishes and owns `src/placement.js` before `realtime` contributes its
|
|
72
|
+
placement, so do not pre-install the shell as a workaround.
|
|
73
|
+
|
|
74
|
+
## Existing-app migration checklist
|
|
75
|
+
|
|
76
|
+
JSKIT is still version 0, so this release uses a direct code migration rather
|
|
77
|
+
than a legacy compatibility layer:
|
|
78
|
+
|
|
79
|
+
1. Commit the app's current work, then run `npm run jskit:update`.
|
|
80
|
+
2. If the app declares `json-rest-schema` directly, install
|
|
81
|
+
`json-rest-schema@^1.0.17`.
|
|
82
|
+
3. Replace resource-bound JavaScript `Date` values with strings. `date` is
|
|
83
|
+
`YYYY-MM-DD`; `time` is offset-free `HH:MM[:SS[.fraction]]`; and `dateTime`
|
|
84
|
+
is RFC 3339 with seconds and a `Z` or numeric offset. Replace the removed
|
|
85
|
+
`timestamp` type with `epochMilliseconds` or `epochSeconds` only after
|
|
86
|
+
checking the existing numeric unit. Preserve `temporalPrecision`.
|
|
87
|
+
4. For a standard generated view delete action, rerun the original
|
|
88
|
+
`crud-ui-generator crud` command with `--delete-confirmation`. Add `--force`
|
|
89
|
+
only when you deliberately want to replace unchanged generated page output.
|
|
90
|
+
For a customized view, preserve the customization and add the public
|
|
91
|
+
`CrudViewScreen` `actions` slot plus `useCrudDeleteAction()` integration
|
|
92
|
+
described below.
|
|
93
|
+
5. Keep every managed path recorded in `.jskit/lock.json`. Adapt managed shell
|
|
94
|
+
and browser tests in place; never delete them because a starter route was
|
|
95
|
+
replaced.
|
|
96
|
+
|
|
97
|
+
Generated generic CRUD repositories convert database temporal values at the
|
|
98
|
+
resource boundary. Custom repositories still need to return strict temporal
|
|
99
|
+
strings and write ISO/RFC 3339 strings explicitly.
|
|
100
|
+
|
|
34
101
|
## The two generator packages
|
|
35
102
|
|
|
36
103
|
### `crud-server-generator` `@jskit-ai/crud-server-generator` `(0.1.47)`
|
|
@@ -449,7 +516,8 @@ npx jskit generate crud-ui-generator crud \
|
|
|
449
516
|
w/[workspaceSlug]/admin/contacts \
|
|
450
517
|
--resource-file packages/contacts/src/shared/contactResource.js \
|
|
451
518
|
--id-param contactId \
|
|
452
|
-
--display-fields fullName,email,phone
|
|
519
|
+
--display-fields fullName,email,phone \
|
|
520
|
+
--delete-confirmation
|
|
453
521
|
```
|
|
454
522
|
|
|
455
523
|
That creates the baseline CRUD route tree:
|
|
@@ -465,6 +533,20 @@ The mirrored component root is intentional. The configured file router scans
|
|
|
465
533
|
Vue files below `src/pages/`, so reusable Vue helpers must stay outside that
|
|
466
534
|
directory or they become browser routes.
|
|
467
535
|
|
|
536
|
+
`--delete-confirmation` is opt-in. When present, the generated view extends
|
|
537
|
+
the public `CrudViewScreen` `actions` slot with a destructive Delete button and
|
|
538
|
+
a Vuetify alert dialog. The public `useCrudDeleteAction()` composable resolves
|
|
539
|
+
the current route id through the CRUD runtime, runs the shared resource's
|
|
540
|
+
`DELETE` operation through `useCommand()`, disables duplicate submission,
|
|
541
|
+
keeps a useful error on the record screen, invalidates the list query, and
|
|
542
|
+
navigates to the generated list route after success. It supports custom
|
|
543
|
+
`--id-param` names.
|
|
544
|
+
|
|
545
|
+
The generator rejects this option when list or view is omitted, or when the
|
|
546
|
+
shared resource has no `DELETE` operation. Without the flag, no delete control
|
|
547
|
+
is generated. Do not substitute raw `fetch()` or import private `users-web`
|
|
548
|
+
modules.
|
|
549
|
+
|
|
468
550
|
Generated list, view, and lookup reads use the resource contract as their
|
|
469
551
|
response authority. They return every field declared for output by default,
|
|
470
552
|
including the target resource's declared output when a lookup relation is
|
package/guide/agent/index.md
CHANGED
|
@@ -40,3 +40,6 @@ It starts with a fast reproducible Quickstart, then steps back to the scaffold-f
|
|
|
40
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
41
|
- Jump into `Generators` if you already understand the runtime packages and want app-owned scaffolding workflows.
|
|
42
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.
|
|
43
|
+
- Updating an existing app for strict temporal values or generated record
|
|
44
|
+
deletion? Go straight to the
|
|
45
|
+
[Existing-app migration checklist](/guide/generators/crud-generators#existing-app-migration-checklist).
|
package/package.json
CHANGED
package/patterns/INDEX.md
CHANGED
|
@@ -18,17 +18,17 @@ How to use it:
|
|
|
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, `crud-server-generator`, `crud-ui-generator`
|
|
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
22
|
- `crud-scaffolding.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`
|
|
26
26
|
- `page-redirects.md`
|
|
27
|
-
- live actions, checkbox, toggle, patch button, inline action, `useCommand()`
|
|
27
|
+
- live actions, checkbox, toggle, patch button, delete confirmation, destructive action, inline action, `useCommand()`, `useCrudDeleteAction()`
|
|
28
28
|
- `live-actions.md`
|
|
29
29
|
- ajax, fetch, API call, request, endpoint, HTTP client, `useCrudListScreen()`, `useCrudViewScreen()`, `useCrudAddEditScreen()`, `useList()`, `useView()`, `useAddEdit()`, `useEndpointResource()`, `usersWebHttpClient`
|
|
30
30
|
- `client-requests.md`
|
|
31
|
-
- playwright, browser test, e2e, ui verification, authenticated ui test, test auth, dev login as, dev auth bypass
|
|
31
|
+
- playwright, browser test, e2e, ui verification, managed test, `.jskit/lock.json`, authenticated ui test, test auth, dev login as, dev auth bypass
|
|
32
32
|
- `ui-testing.md`
|
|
33
33
|
- generated UI contract, design contract, navigation roles, density, placeholder copy, card shells, shared CRUD screens, row actions, synthetic rows, detail slots
|
|
34
34
|
- `generated-ui-contract-tracking.md`
|
|
@@ -36,7 +36,7 @@ How to use it:
|
|
|
36
36
|
- `filters.md`
|
|
37
37
|
- `searchSchema`, `search: true`, `applyFilter`, server search, query validators, backend filters, internal JSON REST filters
|
|
38
38
|
- `server-search.md`
|
|
39
|
-
- `actualField`, `storage.writeSerializer`, `storage.virtual`, computed field, virtual field, projection, `createCrudResourceRuntime`, `remainingBatchWeight`, datetime write serialization
|
|
39
|
+
- `actualField`, `storage.writeSerializer`, `storage.virtual`, computed field, virtual field, projection, `createCrudResourceRuntime`, `remainingBatchWeight`, datetime write serialization, temporalPrecision, json-rest-schema dates
|
|
40
40
|
- `crud-repository-mapping.md`
|
|
41
41
|
- row policy, permission filtering, visibility before pagination, recursive CTE, descendants, package cycle, `RowPolicyPlugin`
|
|
42
42
|
- `row-policies.md`
|
|
@@ -113,6 +113,9 @@ If the resource module is server-only, a field may also declare `storage.queryPr
|
|
|
113
113
|
What CRUD core does for you:
|
|
114
114
|
- default select columns include only column-backed output fields
|
|
115
115
|
- create/update write payloads serialize standard writable `date-time` fields centrally
|
|
116
|
+
- database reads serialize `date`, `time`, and `dateTime` values to their
|
|
117
|
+
strict `json-rest-schema` string contracts before resource validation,
|
|
118
|
+
respecting `temporalPrecision`
|
|
116
119
|
- create/update write payloads also apply any explicit field write serializers centrally
|
|
117
120
|
- `list`, `findById`, `listByIds`, and `listByForeignIds` apply registered virtual projections automatically
|
|
118
121
|
- search and parent-filter fallback derivation only use column-backed fields
|
|
@@ -131,3 +134,5 @@ Review checks:
|
|
|
131
134
|
- computed fields use `storage: { virtual: true }`
|
|
132
135
|
- repository runtime registers matching `virtualFields`, or the JSON REST provider registers matching `queryFields`
|
|
133
136
|
- no per-method projection duplication when generic CRUD reads already cover the field
|
|
137
|
+
- no JavaScript `Date` object crosses a strict resource validation boundary;
|
|
138
|
+
custom repositories return ISO/RFC 3339 strings explicitly
|
|
@@ -14,6 +14,26 @@ Check first:
|
|
|
14
14
|
- `jskit show crud-server-generator --details`
|
|
15
15
|
- whether the request is server-only CRUD or server-plus-UI CRUD
|
|
16
16
|
|
|
17
|
+
## Fresh minimal-app order
|
|
18
|
+
|
|
19
|
+
After `create-app`, run `npm install` before invoking the local CLI, and then
|
|
20
|
+
use `npx --no-install jskit` so a missing local CLI fails clearly. For a fresh
|
|
21
|
+
minimal CRUD app, the complete order is:
|
|
22
|
+
|
|
23
|
+
1. create the app
|
|
24
|
+
2. `npm install`
|
|
25
|
+
3. add the database runtime
|
|
26
|
+
4. `npm install`
|
|
27
|
+
5. create the live table in a fresh disposable development database
|
|
28
|
+
6. run `crud-server-generator scaffold`
|
|
29
|
+
7. `npm install`
|
|
30
|
+
8. run `crud-ui-generator crud`
|
|
31
|
+
|
|
32
|
+
The server generator resolves its complete package dependency closure. In
|
|
33
|
+
particular, `shell-web` owns and establishes `src/placement.js` before
|
|
34
|
+
`realtime` appends its placement. Do not pre-install `shell-web` as a
|
|
35
|
+
workaround.
|
|
36
|
+
|
|
17
37
|
## Non-negotiable database contract
|
|
18
38
|
|
|
19
39
|
Before database, schema, CRUD, repository, or persistence work, read this
|
|
@@ -75,6 +95,29 @@ Rules:
|
|
|
75
95
|
- Bulk actions should be declared in the generated page-local `listBulkActions.js`. The generated list owns selection state, keeps selection controls hidden until actions exist, and exposes selected ids/records to action handlers.
|
|
76
96
|
- Structured filters should use shared filter definitions and collapse to compact filter controls/sheets when they outgrow simple search. Do not stack dense desktop filter bars on phone widths.
|
|
77
97
|
- Use `--navigation-role` for CRUD list placement intent. Main resources can stay `primary`; nested/detail/workflow CRUD routes should usually be `secondary`, `workflow`, or `none`.
|
|
98
|
+
- Add `--delete-confirmation` when the generated view needs the standard
|
|
99
|
+
destructive record action. The flag requires list and view pages and a
|
|
100
|
+
resource with a `DELETE` operation; it uses the public view-screen action
|
|
101
|
+
slot and command composable rather than generated raw request code.
|
|
102
|
+
|
|
103
|
+
## Temporal values at resource boundaries
|
|
104
|
+
|
|
105
|
+
`json-rest-schema` 1.0.17 accepts strict string temporal values. Resource
|
|
106
|
+
validators no longer coerce JavaScript `Date` objects:
|
|
107
|
+
|
|
108
|
+
- `date` is `YYYY-MM-DD`
|
|
109
|
+
- `time` is offset-free `HH:MM[:SS[.fraction]]`
|
|
110
|
+
- `dateTime` is RFC 3339 with seconds and `Z` or a numeric offset
|
|
111
|
+
|
|
112
|
+
The removed `timestamp` type must become `epochMilliseconds` or
|
|
113
|
+
`epochSeconds` after checking the stored unit. Preserve the field's
|
|
114
|
+
`temporalPrecision`; do not truncate meaningful fractional seconds.
|
|
115
|
+
|
|
116
|
+
Generated generic CRUD repositories serialize database temporal outputs
|
|
117
|
+
before resource validation. App-owned/custom repositories must return strict
|
|
118
|
+
strings and must write ISO/RFC 3339 strings rather than passing `Date` objects.
|
|
119
|
+
This is a version-0 breaking contract: update application code instead of
|
|
120
|
+
adding a legacy temporal parser.
|
|
78
121
|
|
|
79
122
|
## Baseline generation versus later schema evolution
|
|
80
123
|
|
|
@@ -52,7 +52,7 @@ Generated JSKIT apps should feel like real adaptive apps by default, not framewo
|
|
|
52
52
|
- Do not remove intentional cards from specialist UI components just to satisfy a broad scan.
|
|
53
53
|
- Keep generated files deterministic and update catalog/agent-doc outputs when descriptors or exported symbols change.
|
|
54
54
|
- Kernel shared UI contract must stay surface-id agnostic. Concrete mappings like admin/console to operator profile belong in generators or package templates.
|
|
55
|
-
- Item 3 is complete for current generated surfaces: page, CRUD, shell, and starter outputs require compact/medium/expanded coverage, horizontal overflow checks, generated screen checks, and 48px tap target checks. Calendar/grid/bottom-sheet specialist generators remain future scope until those generators exist.
|
|
55
|
+
- Item 3 is complete for current generated surfaces: page, CRUD, shell, and starter outputs require compact/medium/expanded coverage, horizontal overflow checks, generated screen checks, and compact generated-screen 48px tap target checks. Calendar/grid/bottom-sheet specialist generators remain future scope until those generators exist.
|
|
56
56
|
- Item 5 is complete for current generators: `primary`, `secondary`, `utility`, `detail`, `workflow`, and `none` are centralized in the generated UI contract, generators consume that contract, and `utility` resolves to seeded `shell.global-actions` topology.
|
|
57
57
|
- Item 6 is complete for the default shell: compact app bars use compact density and bounded top-left/top-right regions, while primary navigation remains in semantic bottom navigation instead of app-bar chrome.
|
|
58
58
|
- CRUD filters are client-side by default: generated list pages create a page-local `listFilters.js` and pass it into `useCrudListScreen(...)`; the shared list screen wires `filterRuntime.queryParams` into the list request and renders `CrudListFilterSurface`. When server filtering is needed, promote the definitions into a shared package module and use `createCrudListFilterContract(...)` so route/action validators, JSON REST search schema, and repository query normalization stay derived from the same definition.
|
package/patterns/live-actions.md
CHANGED
|
@@ -12,6 +12,25 @@ Rules:
|
|
|
12
12
|
- Prefer `useCommand()` for live actions.
|
|
13
13
|
- Prefer form runtimes such as `useCrudAddEdit()` or `useAddEdit()` for real forms.
|
|
14
14
|
- Prefer `useCrudList()` and `useCrudView()` for routed CRUD loading and URL resolution.
|
|
15
|
+
- For ordinary routed CRUD record deletion, generate the supported lane instead
|
|
16
|
+
of rebuilding it page by page:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx --no-install jskit generate crud-ui-generator crud notes \
|
|
20
|
+
--resource-file packages/notes/src/shared/noteResource.js \
|
|
21
|
+
--id-param noteId \
|
|
22
|
+
--display-fields title,body \
|
|
23
|
+
--parent-title contextual \
|
|
24
|
+
--navigation-role primary \
|
|
25
|
+
--delete-confirmation
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`--delete-confirmation` requires generated list and view pages plus a shared
|
|
29
|
+
resource with a `DELETE` operation. It extends the view through the public
|
|
30
|
+
`CrudViewScreen` `actions` slot and `useCrudDeleteAction()`: Vuetify owns the
|
|
31
|
+
alert dialog, `useCommand()` owns the request state, the shared resource owns
|
|
32
|
+
the DELETE contract, and successful deletion invalidates the list query and
|
|
33
|
+
navigates to the generated list route.
|
|
15
34
|
|
|
16
35
|
Good live-action pattern:
|
|
17
36
|
|
|
@@ -30,4 +49,6 @@ Examples:
|
|
|
30
49
|
Avoid:
|
|
31
50
|
|
|
32
51
|
- manually hand-rolling fetch logic for a standard live action when `useCommand()` fits
|
|
52
|
+
- inspecting private `users-web` internals or creating a page-local transport
|
|
53
|
+
for generated record deletion
|
|
33
54
|
- pushing derived write rules into the client just because the action is small
|
package/patterns/ui-testing.md
CHANGED
|
@@ -11,7 +11,7 @@ Rules:
|
|
|
11
11
|
|
|
12
12
|
- Any chunk that adds or changes user-facing UI must include a Playwright flow that exercises the changed behavior before the chunk is done.
|
|
13
13
|
- Generator or package template UI changes must be checked at compact phone, tablet-ish medium, and expanded desktop widths.
|
|
14
|
-
- For generated UI, check horizontal overflow, clipped or invisible text, duplicate navigation, broken route placement,
|
|
14
|
+
- For generated UI, check horizontal overflow, clipped or invisible text, duplicate navigation, and broken route placement at every standard viewport. On compact screens, also check generated-screen tap targets under 48 px; medium and expanded layouts may use their documented denser controls.
|
|
15
15
|
- Apps with `shell-web` installed should start from `tests/e2e/adaptive-shell.spec.ts` and extend it with feature-specific assertions.
|
|
16
16
|
- Generated `playwright.config.mjs` delegates to `@jskit-ai/jskit-cli/test/playwright`. Do not copy base-URL, web-server, or storage-state logic into app tests.
|
|
17
17
|
- Use relative paths such as `page.goto("/home")`. The shared config owns the browser base URL.
|
|
@@ -19,6 +19,18 @@ Rules:
|
|
|
19
19
|
- Vibe64 supplies an authenticated context through `VIBE64_PLAYWRIGHT_STORAGE_STATE`. Treat that file as a temporary secret: do not commit it, print it, or retain it after the run.
|
|
20
20
|
- Do not install a browser when the environment provides a managed browser runner.
|
|
21
21
|
|
|
22
|
+
## Preserve managed baseline tests
|
|
23
|
+
|
|
24
|
+
“App-owned” means customizable, not disposable while the package remains
|
|
25
|
+
installed. Never delete or rename a test path recorded in `.jskit/lock.json`.
|
|
26
|
+
Generated and managed infrastructure tests must be adapted in place.
|
|
27
|
+
|
|
28
|
+
When the starter product route is replaced, update the scaffold smoke test to
|
|
29
|
+
visit and assert the new canonical route. Do not delete baseline browser
|
|
30
|
+
coverage such as `tests/e2e/base-shell.spec.ts` or
|
|
31
|
+
`tests/e2e/adaptive-shell.spec.ts`. JSKIT Doctor must continue to flag a
|
|
32
|
+
managed test that is missing.
|
|
33
|
+
|
|
22
34
|
## Direct local authentication
|
|
23
35
|
|
|
24
36
|
Use the development-only dev auth bypass when Playwright is talking directly to an app running on localhost.
|
|
@@ -223,7 +223,7 @@ Exports
|
|
|
223
223
|
- `requireCrudTableName(tableName, { context = "crudRepository" } = {})`
|
|
224
224
|
- `deriveRepositoryMappingFromResource(resource = {}, { context = "crudRepository" } = {})`
|
|
225
225
|
- `applyCrudListQueryFilters(query, { idColumn = "id", cursor = "", applyCursor = true, q = "", searchColumns = [], parentFilters = {}, parentFilterColumns = {} } = {})`
|
|
226
|
-
- `mapRecordRow(row, fieldKeys = [], overrides = {}, { recordIdKeys = [] } = {})`
|
|
226
|
+
- `mapRecordRow(row, fieldKeys = [], overrides = {}, { recordIdKeys = [], serializerByKey = {} } = {})`
|
|
227
227
|
- `buildWritePayload(sourcePayload = {}, fieldKeys = [], overrides = {}, { serializerByKey = {} } = {})`
|
|
228
228
|
- `resolveColumnName(fieldKey, overrides = {})`
|
|
229
229
|
- `resolveCrudIdColumn(idColumn, { fallback = "id" } = {})`
|
|
@@ -33,6 +33,7 @@ Local functions
|
|
|
33
33
|
- `parseOperationsOption(options)`
|
|
34
34
|
- `parseDisplayFieldsOption(options)`
|
|
35
35
|
- `parseParentTitleOption(options)`
|
|
36
|
+
- `resolveBooleanFlagOption(options = {}, optionName = "")`
|
|
36
37
|
- `shouldCreateNavigationLink(options = {}, inferenceContext = {})`
|
|
37
38
|
- `resolveNavigationRoleLinkPlacement(options = {}, inferenceContext = {})`
|
|
38
39
|
- `validateDisplayFieldsForOperation(selectedFieldKeys, fields, operationName)`
|
|
@@ -60,6 +61,9 @@ Local functions
|
|
|
60
61
|
- `resolveCrudRelativePath(namespace = "")`
|
|
61
62
|
- `buildListParentTitleImportLine(parentTitleMode = "contextual")`
|
|
62
63
|
- `buildListHeadingTitleSetup({ parentTitleMode = "contextual", resourceNamespace = "", routeTitle = "Records" } = {})`
|
|
64
|
+
- `buildViewDeleteActionSlot({ resourceNamespace = "resource", resourceSingularTitle = "Record" } = {})`
|
|
65
|
+
- `buildViewDeleteDialog({ resourceNamespace = "resource", resourceSingularTitle = "Record" } = {})`
|
|
66
|
+
- `buildViewDeleteSetup({ resourceNamespace = "resource" } = {})`
|
|
63
67
|
|
|
64
68
|
### `src/server/resourceSupport.js`
|
|
65
69
|
Exports
|
|
@@ -95,6 +99,7 @@ Local functions
|
|
|
95
99
|
- `resolveSchemaReference(ref = "", rootSchema = {}, { context = "ui-generator", contextLabel = "schema" } = {})`
|
|
96
100
|
- `resolveObjectSchema(schema = {}, contextLabel, { context = "ui-generator", rootSchema = schema } = {})`
|
|
97
101
|
- `resolveJsonRestCastType(schema = {})`
|
|
102
|
+
- `resolveTemporalPrecision(...schemas)`
|
|
98
103
|
- `resolveSchemaType(schema)`
|
|
99
104
|
- `toFieldLabel(key)`
|
|
100
105
|
- `isSupportedSelectOptionValue(value)`
|
|
@@ -108,6 +113,7 @@ Local functions
|
|
|
108
113
|
- `toLookupRelation(fieldContractMap = {}, fieldKey = "", { lookupContainerKey = "lookups" } = {})`
|
|
109
114
|
- `resolveFormInputType(fieldType, fieldFormat)`
|
|
110
115
|
- `resolveFormFieldComponent(fieldType, relation = null)`
|
|
116
|
+
- `resolveTemporalInputStep(field = {})`
|
|
111
117
|
- `buildDefaultNullableBooleanOptions()`
|
|
112
118
|
- `toPositiveInteger(value)`
|
|
113
119
|
- `toAccessorExpression(baseName, fieldKey)`
|
|
@@ -53,9 +53,18 @@ Exports
|
|
|
53
53
|
- `toInsertDateTime(dateLike, fallback = new Date())`
|
|
54
54
|
- `toNullableDateTime(value)`
|
|
55
55
|
- `toDatabaseDateTimeUtc(value)`
|
|
56
|
+
- `toJsonDate(value)`
|
|
57
|
+
- `toJsonTime(value, { temporalPrecision } = {})`
|
|
58
|
+
- `toJsonDateTime(value, { temporalPrecision } = {})`
|
|
56
59
|
Local functions
|
|
57
60
|
- `toDateOrThrow(value)`
|
|
58
61
|
- `pad(value, size = 2)`
|
|
62
|
+
- `requireValidDateParts(year, month, day)`
|
|
63
|
+
- `requireValidTimeParts(hours, minutes, seconds = 0)`
|
|
64
|
+
- `parseDateParts(value)`
|
|
65
|
+
- `normalizeTemporalPrecision(value)`
|
|
66
|
+
- `formatFraction(milliseconds, temporalPrecision)`
|
|
67
|
+
- `requireAllowedFraction(fraction, temporalPrecision)`
|
|
59
68
|
|
|
60
69
|
### `src/shared/dialect.js`
|
|
61
70
|
Exports
|
|
@@ -84,6 +93,9 @@ Exports
|
|
|
84
93
|
- `toInsertDateTime`
|
|
85
94
|
- `toNullableDateTime`
|
|
86
95
|
- `toDatabaseDateTimeUtc`
|
|
96
|
+
- `toJsonDate`
|
|
97
|
+
- `toJsonTime`
|
|
98
|
+
- `toJsonDateTime`
|
|
87
99
|
- `normalizeDialect`
|
|
88
100
|
- `detectDialectFromClient`
|
|
89
101
|
- `normalizeText`
|
|
@@ -41,9 +41,10 @@ Local functions
|
|
|
41
41
|
- `cloneJsonRestResourceValue(value, { writeSerializers = {} } = {})`
|
|
42
42
|
- `resolveCanonicalCalendarDate(value)`
|
|
43
43
|
- `serializeJsonRestCalendarDate(value)`
|
|
44
|
+
- `resolveCanonicalDateTime(value)`
|
|
44
45
|
- `applyJsonRestCalendarDateWriteSerializers(scopeOptions = {})`
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
46
|
+
- `normalizeJsonRestTemporalEntry(entry = null, scopes = {})`
|
|
47
|
+
- `normalizeJsonRestTemporalDocument(document = null, scopes = {})`
|
|
47
48
|
- `normalizeScopeValue(value)`
|
|
48
49
|
- `normalizeJsonRestText(value, { fallback = "" } = {})`
|
|
49
50
|
- `normalizeJsonRestFilterValue(value)`
|
|
@@ -66,6 +66,7 @@ Exports
|
|
|
66
66
|
- None
|
|
67
67
|
Local functions
|
|
68
68
|
- `handlePullPointerDown(event)`
|
|
69
|
+
- `handleDrawerVisibilityChange(open)`
|
|
69
70
|
- `handlePullPointerMove(event)`
|
|
70
71
|
- `handlePullPointerEnd(event)`
|
|
71
72
|
- `handlePullPointerCancel(event)`
|
|
@@ -404,6 +405,13 @@ Local functions
|
|
|
404
405
|
Exports
|
|
405
406
|
- `useShellLayoutStore`
|
|
406
407
|
|
|
408
|
+
### `src/client/support/drawerPresentation.js`
|
|
409
|
+
Exports
|
|
410
|
+
- `DESKTOP_DRAWER_CLOSED_MODES`
|
|
411
|
+
- `normalizeDesktopDrawerClosedMode(value = "rail")`
|
|
412
|
+
- `resolveShellDrawerPresentation({ compact = false, open = false, desktopClosedMode = "rail" } = {})`
|
|
413
|
+
- `resolveShellDrawerToggleLabel({ compact = false, open = false } = {})`
|
|
414
|
+
|
|
407
415
|
### `src/client/support/menuLinkTarget.js`
|
|
408
416
|
Exports
|
|
409
417
|
- `normalizeMenuLinkPathname(pathname = "")`
|
|
@@ -124,15 +124,12 @@ Exports
|
|
|
124
124
|
|
|
125
125
|
### `src/server/common/repositories/repositoryUtils.js`
|
|
126
126
|
Exports
|
|
127
|
-
- `toNullableDateTime`
|
|
128
127
|
- `toIsoString`
|
|
129
128
|
- `isDuplicateEntryError`
|
|
130
129
|
- `normalizeText`
|
|
131
130
|
- `normalizeLowerText`
|
|
132
131
|
- `normalizeRecordId`
|
|
133
132
|
- `normalizeDbRecordId`
|
|
134
|
-
- `nowDb()`
|
|
135
|
-
- `toNullableIso(value)`
|
|
136
133
|
- `uniqueSorted(values)`
|
|
137
134
|
- `parseJson(value, fallback = {})`
|
|
138
135
|
- `toDbJson(value, fallback = {})`
|
|
@@ -209,7 +209,8 @@ Local functions
|
|
|
209
209
|
- `toTimeInputValue(value)`
|
|
210
210
|
- `toDateTimeLocalInputValue(value)`
|
|
211
211
|
- `toDateInputValue(value)`
|
|
212
|
-
- `
|
|
212
|
+
- `applyDateTimePrecision(isoValue, temporalPrecision)`
|
|
213
|
+
- `toIsoUtcDateTimeValue(value, temporalPrecision)`
|
|
213
214
|
- `resolveFormFieldInitialValue(field = {})`
|
|
214
215
|
- `shouldSerializeClearedFieldAsNull(field = {})`
|
|
215
216
|
|
|
@@ -488,6 +489,15 @@ Exports
|
|
|
488
489
|
Local functions
|
|
489
490
|
- `normalizeProvidedScreen(screen = null)`
|
|
490
491
|
|
|
492
|
+
### `src/client/composables/useCrudDeleteAction.js`
|
|
493
|
+
Exports
|
|
494
|
+
- `requireCrudDeleteOperation(resource = null)`
|
|
495
|
+
- `resolveDeleteApiSuffix(screen, apiUrlTemplate = "")`
|
|
496
|
+
- `useCrudDeleteAction({ screen = null, resource = null, resourceNamespace = "", apiUrlTemplate = "", access = "auto", client = null, router: routerOverride = null, fallbackDeleteError = "Unable to delete record." } = {})`
|
|
497
|
+
Local functions
|
|
498
|
+
- `requireCrudViewScreen(screen = null)`
|
|
499
|
+
- `resolveListLocation(screen)`
|
|
500
|
+
|
|
491
501
|
### `src/client/composables/useCrudListBulkActions.js`
|
|
492
502
|
Exports
|
|
493
503
|
- `useCrudListBulkActions(actions = [], { resolveRecordId = null, resolveContext = null } = {})`
|
|
@@ -616,6 +626,7 @@ Exports
|
|
|
616
626
|
- `CrudViewScreen`
|
|
617
627
|
- `normalizeCrudApiAccess`
|
|
618
628
|
- `resolveCrudHttpClient`
|
|
629
|
+
- `useCrudDeleteAction`
|
|
619
630
|
- `clientProviders`
|
|
620
631
|
|
|
621
632
|
### `src/client/lib/bootstrap.js`
|
|
@@ -38,15 +38,12 @@ Exports
|
|
|
38
38
|
|
|
39
39
|
### `src/server/common/repositories/repositoryUtils.js`
|
|
40
40
|
Exports
|
|
41
|
-
- `toNullableDateTime`
|
|
42
41
|
- `toIsoString`
|
|
43
42
|
- `isDuplicateEntryError`
|
|
44
43
|
- `normalizeText`
|
|
45
44
|
- `normalizeLowerText`
|
|
46
45
|
- `normalizeRecordId`
|
|
47
46
|
- `normalizeDbRecordId`
|
|
48
|
-
- `nowDb()`
|
|
49
|
-
- `toNullableIso(value)`
|
|
50
47
|
- `uniqueSorted(values)`
|
|
51
48
|
- `parseJson(value, fallback = {})`
|
|
52
49
|
- `toDbJson(value, fallback = {})`
|
package/skills/jskit/SKILL.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jskit
|
|
3
|
-
description: Build, extend, troubleshoot, review, deslop, and verify JSKIT
|
|
3
|
+
description: Build, extend, troubleshoot, review, deslop, and verify JSKIT apps using its CLI, packages, generators, surfaces, placements, CRUDs, managed files, and verification conventions.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# JSKIT
|
|
7
7
|
|
|
8
|
-
Use JSKIT's
|
|
9
|
-
|
|
10
|
-
files define the product.
|
|
8
|
+
Use JSKIT's CLI, generators, packages, and app-local contracts. The request
|
|
9
|
+
and app files define the product.
|
|
11
10
|
|
|
12
11
|
## Exact caller lanes
|
|
13
12
|
|
|
@@ -24,9 +23,7 @@ Discover only a missing fact or exact-command failure, then resume the lane.
|
|
|
24
23
|
1. Read the request and nearest `AGENTS.md`.
|
|
25
24
|
2. Inspect `package.json`, `.jskit/lock.json`, the existing tree, and the
|
|
26
25
|
current diff when reviewing changes.
|
|
27
|
-
3. Read `.jskit/APP_BLUEPRINT.md` when present
|
|
28
|
-
architecture decisions. Do not invent or expand product requirements from
|
|
29
|
-
this skill.
|
|
26
|
+
3. Read `.jskit/APP_BLUEPRINT.md` when present; do not invent requirements.
|
|
30
27
|
4. Load only the task-relevant direct reference:
|
|
31
28
|
- For creation, package selection, CLI use, or generators, read
|
|
32
29
|
[application operations](references/app-operations.md).
|
|
@@ -36,73 +33,43 @@ Discover only a missing fact or exact-command failure, then resume the lane.
|
|
|
36
33
|
[UI operations](references/ui-operations.md).
|
|
37
34
|
|
|
38
35
|
Those files are the complete operational references required by this skill.
|
|
39
|
-
Do not depend on sibling
|
|
40
|
-
irrelevant references.
|
|
36
|
+
Do not depend on sibling docs. Do not load irrelevant references.
|
|
41
37
|
|
|
42
38
|
Do not invent missing tenancy, authentication, database, surface, ownership,
|
|
43
39
|
or permission decisions when they would materially change the application.
|
|
44
40
|
|
|
45
41
|
## Discovery fallback
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- Treat `.jskit/lock.json` and JSKIT-owned projections as managed state. Do not
|
|
51
|
-
hand-edit the lock or bypass managed-file lifecycle checks.
|
|
43
|
+
Use the narrowest CLI query for a missing fact. Prefer existing packages,
|
|
44
|
+
generators, placements, and high-level composables. Never hand-edit
|
|
45
|
+
`.jskit/lock.json` or bypass managed-file lifecycle checks.
|
|
52
46
|
|
|
53
47
|
## Implement a change
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
requires them.
|
|
61
|
-
5. For schema work, use only a fresh disposable development database; never
|
|
62
|
-
alter production, legacy, historical, or otherwise valuable data.
|
|
63
|
-
|
|
64
|
-
For user-facing work, respect the selected surface and semantic placements,
|
|
65
|
-
handle compact layouts and loading, empty, error, permission, and ownership
|
|
66
|
-
states, and verify meaningful behavior in the browser.
|
|
49
|
+
Read the matching reference and implement the smallest complete slice at
|
|
50
|
+
documented seams. Install dependencies/migrate only when required. Use only a
|
|
51
|
+
fresh disposable development database for schema work—never valuable data.
|
|
52
|
+
For UI, respect surface/placements, compact layout, all operational states,
|
|
53
|
+
permissions/ownership, and browser verification.
|
|
67
54
|
|
|
68
55
|
## Caller-owned verification
|
|
69
56
|
|
|
70
|
-
When a
|
|
71
|
-
|
|
72
|
-
within its wall-time and action limits, implement the requested slice, return
|
|
73
|
-
the requested manifest or summary, and stop. Do not start a dev server,
|
|
57
|
+
When a caller owns tests, migrations, server lifecycle, browser checks, or
|
|
58
|
+
sign-off, honor that division and its limits. Do not start a dev server,
|
|
74
59
|
browser, Playwright, broad verifier, migration rebuild, or exploratory review
|
|
75
|
-
unless
|
|
60
|
+
unless requested in the current task.
|
|
76
61
|
|
|
77
62
|
## Review or deslop
|
|
78
63
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- Duplicated helpers, dead code, placeholders, accidental abstractions, and
|
|
85
|
-
incomplete states.
|
|
86
|
-
- Missed JSKIT packages, generators, high-level composables, placements, or
|
|
87
|
-
runtime seams.
|
|
88
|
-
- Invalid surface, route, ownership, permission, migration, or managed-file
|
|
89
|
-
choices.
|
|
90
|
-
- Weak Material Design or Vuetify hierarchy, responsiveness, actions, and
|
|
91
|
-
state handling.
|
|
92
|
-
- Verification proportional to scope, including Playwright for meaningful
|
|
93
|
-
user-facing flows.
|
|
94
|
-
|
|
95
|
-
Present findings first, ordered by severity, with file references. Say
|
|
96
|
-
explicitly when there are no findings.
|
|
64
|
+
For review-only work, report without editing. Check duplicated/dead/wrong code,
|
|
65
|
+
accidental abstraction, incomplete states, missed high-level JSKIT seams,
|
|
66
|
+
invalid routing/ownership/permission/migration/managed-file choices, weak
|
|
67
|
+
Vuetify/Material behavior, and proportional verification. Put findings first
|
|
68
|
+
by severity with file references; state when none exist.
|
|
97
69
|
|
|
98
70
|
## Verify
|
|
99
71
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
- Rebuild migrations from zero against a fresh disposable database when
|
|
105
|
-
schema or persistence changed.
|
|
106
|
-
- Run the relevant Playwright flow when user-facing behavior changed.
|
|
107
|
-
- Report files reviewed or changed, commands run, and anything still
|
|
108
|
-
unverified.
|
|
72
|
+
Run focused tests for a slice and broad checks for a whole changeset. Run
|
|
73
|
+
Doctor for managed state, `npm run verify` before sign-off, rebuild changed
|
|
74
|
+
persistence from zero in a disposable database, and use Playwright for UI.
|
|
75
|
+
Report files, commands, and anything unverified.
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# Application operations
|
|
2
2
|
|
|
3
|
-
Read this
|
|
4
|
-
and generator selection.
|
|
3
|
+
Read this for app creation, CLI discovery, packages, and generators.
|
|
5
4
|
|
|
6
5
|
## Create an application
|
|
7
6
|
|
|
8
|
-
Confirm the
|
|
7
|
+
Confirm the name and tenancy mode:
|
|
9
8
|
|
|
10
9
|
```bash
|
|
11
10
|
npx @jskit-ai/create-app <app-name> --tenancy-mode <tenancy-mode>
|
|
@@ -13,29 +12,56 @@ cd <app-name>
|
|
|
13
12
|
npm install
|
|
14
13
|
```
|
|
15
14
|
|
|
16
|
-
Generated
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`AGENTS.md`.
|
|
15
|
+
Generated apps require Node.js 26. Use `--target . --force` only to promote a
|
|
16
|
+
known JSKIT `ai-seed`, never to overwrite an arbitrary app. `--minimal` is for
|
|
17
|
+
deliberately bare package-development or unusual integrations. Follow the
|
|
18
|
+
generated `AGENTS.md`.
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
After the first install, use `npx --no-install jskit ...`; a missing local CLI
|
|
21
|
+
must fail instead of silently fetching another version. Do not add auth, users,
|
|
22
|
+
workspaces, console, sample data, or another database adapter unless requested.
|
|
23
|
+
|
|
24
|
+
## Fresh minimal database CRUD order
|
|
25
|
+
|
|
26
|
+
Use this order exactly: create-app, install, add the database runtime, install,
|
|
27
|
+
create the live table in a fresh disposable development database, generate the
|
|
28
|
+
server CRUD, install, then generate the UI.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @jskit-ai/create-app notes \
|
|
32
|
+
--target . --force --tenancy-mode none --minimal
|
|
33
|
+
npm install
|
|
34
|
+
npx --no-install jskit add package database-runtime-mysql
|
|
35
|
+
npm install
|
|
36
|
+
# Create/select a fresh disposable database and create its live `notes` table.
|
|
37
|
+
npx --no-install jskit generate crud-server-generator scaffold \
|
|
38
|
+
--namespace notes \
|
|
39
|
+
--surface home \
|
|
40
|
+
--ownership-filter public \
|
|
41
|
+
--access public \
|
|
42
|
+
--table-name notes
|
|
43
|
+
npm install
|
|
44
|
+
npx --no-install jskit generate crud-ui-generator crud notes \
|
|
45
|
+
--resource-file packages/notes/src/shared/noteResource.js \
|
|
46
|
+
--id-param noteId \
|
|
47
|
+
--display-fields title,body \
|
|
48
|
+
--parent-title contextual \
|
|
49
|
+
--navigation-role primary \
|
|
50
|
+
--delete-confirmation
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The server generator owns its dependency closure. Do not pre-install
|
|
54
|
+
`shell-web` as a placement workaround.
|
|
24
55
|
|
|
25
56
|
## Select and apply technology
|
|
26
57
|
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
- Install
|
|
30
|
-
|
|
31
|
-
- Run tooling
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Packages own reusable framework behavior. Generators create application-owned
|
|
39
|
-
pages, components, placements, migrations, and support files. Prefer the
|
|
40
|
-
narrowest installed package or generator that implements the requested
|
|
41
|
-
vertical slice; do not build a parallel local framework around it.
|
|
58
|
+
- Discover with `npx --no-install jskit list` and
|
|
59
|
+
`npx --no-install jskit show <id> --details`.
|
|
60
|
+
- Install runtime capability with `npx --no-install jskit add package <id>`;
|
|
61
|
+
inspect a bundle before adding it.
|
|
62
|
+
- Run tooling with `npx --no-install jskit generate <generator> <action> ...`;
|
|
63
|
+
do not install generators as runtime packages.
|
|
64
|
+
- JSKIT owns app mutations, npm owns dependency installation, and
|
|
65
|
+
`npm run db:migrate` owns database migration execution.
|
|
66
|
+
- Continue only at documented app-owned seams. Prefer the narrowest existing
|
|
67
|
+
package or generator over a parallel local framework.
|
|
@@ -1,47 +1,36 @@
|
|
|
1
1
|
# CRUD operations
|
|
2
2
|
|
|
3
|
-
Read this
|
|
4
|
-
|
|
3
|
+
Read this completely before database, schema, CRUD, repository, or persistence
|
|
4
|
+
work.
|
|
5
5
|
|
|
6
6
|
## Establish the contract
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Take the database adapter, surface, access, and ownership from the request and
|
|
9
|
+
app authority. Inspect only a generator whose exact lane or option values are
|
|
10
|
+
missing, or whose supplied command failed:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npx jskit show crud-server-generator --details
|
|
14
|
-
npx jskit show crud-ui-generator --details
|
|
13
|
+
npx --no-install jskit show crud-server-generator --details
|
|
14
|
+
npx --no-install jskit show crud-ui-generator --details
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Never run these merely to reconfirm caller-supplied facts.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- Use only direct `workspace_id` and/or `user_id` columns for generated JSKIT
|
|
27
|
-
ownership and choose the ownership filter matching those columns exactly.
|
|
28
|
-
- Treat names such as `recipient_user_id`, `created_by_user_id`, and
|
|
29
|
-
`assignee_user_id` as domain relationships, not ownership aliases.
|
|
30
|
-
- Express tenant-safe relationships as direct ownership plus a normal
|
|
31
|
-
`parent_id -> parent.id` relation. Test both allowed and cross-workspace
|
|
32
|
-
cases.
|
|
33
|
-
|
|
34
|
-
Stop before generation if the schema uses composite relationship keys or if
|
|
35
|
-
the ownership filter and reserved ownership columns disagree.
|
|
19
|
+
Normal app-owned CRUD tables use one non-null integer primary key. Every
|
|
20
|
+
foreign key is single-column and targets that key; multi-column unique indexes
|
|
21
|
+
are business constraints, never relationship targets. Only direct
|
|
22
|
+
`workspace_id` and `user_id` columns are generated ownership. Names such as
|
|
23
|
+
`recipient_user_id` are domain relationships. Match the ownership filter to
|
|
24
|
+
the reserved columns exactly, and test allowed plus cross-workspace cases.
|
|
25
|
+
Stop before generation when these contracts disagree.
|
|
36
26
|
|
|
37
27
|
## Conventional one-table CRUD
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
the UI:
|
|
29
|
+
Create the validated table first in a fresh disposable development database;
|
|
30
|
+
the server generator reads its live shape:
|
|
42
31
|
|
|
43
32
|
```bash
|
|
44
|
-
npx jskit generate crud-server-generator scaffold \
|
|
33
|
+
npx --no-install jskit generate crud-server-generator scaffold \
|
|
45
34
|
--namespace <resource> \
|
|
46
35
|
--surface <surface> \
|
|
47
36
|
--ownership-filter <public|user|workspace|workspace_user> \
|
|
@@ -49,63 +38,82 @@ npx jskit generate crud-server-generator scaffold \
|
|
|
49
38
|
--table-name <table>
|
|
50
39
|
```
|
|
51
40
|
|
|
52
|
-
Use
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
repository/service/resource/migration ownership chain but no public HTTP CRUD
|
|
57
|
-
routes.
|
|
41
|
+
Use public access only on a non-workspace surface with public ownership. A
|
|
42
|
+
workspace CRUD chooses exactly one of `--grant-role <role>` or
|
|
43
|
+
`--no-role-grant`; never invent a role. `--internal` keeps the generated
|
|
44
|
+
repository/service/resource ownership chain but suppresses public HTTP routes.
|
|
58
45
|
|
|
59
|
-
Run `npm install`, then
|
|
46
|
+
Run `npm install`, then generate UI from the exact shared resource:
|
|
60
47
|
|
|
61
48
|
```bash
|
|
62
|
-
npx jskit generate crud-ui-generator crud \
|
|
49
|
+
npx --no-install jskit generate crud-ui-generator crud \
|
|
63
50
|
<pages-root>/<plural-route> \
|
|
64
51
|
--resource-file packages/<namespace>/src/shared/<singular>Resource.js \
|
|
65
52
|
--parent-title contextual
|
|
66
53
|
```
|
|
67
54
|
|
|
68
55
|
The target is relative to `src/pages/`, starts with the selected surface's
|
|
69
|
-
nonempty configured `pagesRoot
|
|
70
|
-
|
|
71
|
-
only the plural route
|
|
72
|
-
|
|
56
|
+
nonempty configured `pagesRoot` (for example `home/books`), and has no leading
|
|
57
|
+
slash. For a surface deliberately configured with an empty root, use
|
|
58
|
+
only the plural route. Use the exact singular resource filename emitted by the server generator; do not guess it.
|
|
59
|
+
|
|
60
|
+
That resource is canonical. Do not hand-build routes, validators, HTTP helpers,
|
|
61
|
+
or UI before it exists. Prefer `useCrudListScreen()`, `useCrudViewScreen()`, and
|
|
62
|
+
`useCrudAddEditScreen()` for routed screens; the corresponding `useCrud*()`
|
|
63
|
+
composables for routed behavior; and `useList()`, `useView()`, `useAddEdit()`,
|
|
64
|
+
`useCommand()`, or `useEndpointResource()` for non-standard contracts. Standard
|
|
65
|
+
CRUD derives JSON:API transport from the resource—never use raw `fetch()`.
|
|
66
|
+
|
|
67
|
+
## Generated record deletion
|
|
68
|
+
|
|
69
|
+
Request ordinary routed deletion explicitly:
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
```bash
|
|
72
|
+
npx --no-install jskit generate crud-ui-generator crud notes \
|
|
73
|
+
--resource-file packages/notes/src/shared/noteResource.js \
|
|
74
|
+
--id-param noteId \
|
|
75
|
+
--display-fields title,body \
|
|
76
|
+
--parent-title contextual \
|
|
77
|
+
--navigation-role primary \
|
|
78
|
+
--delete-confirmation
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`--delete-confirmation` requires generated list and view pages and a shared
|
|
82
|
+
resource with a `DELETE` operation. It supports a custom `--id-param` and fails
|
|
83
|
+
clearly when the contract is unsupported. The view uses the public
|
|
84
|
+
`CrudViewScreen` `actions` slot and `useCrudDeleteAction()`. A Vuetify alert
|
|
85
|
+
dialog provides Cancel/Delete; `useCommand()` owns pending/error state and the
|
|
86
|
+
resource request; success invalidates the CRUD list and navigates there. Do not
|
|
87
|
+
inspect private `users-web` code, add a page transport, or use raw `fetch()`.
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
## Strict temporal values
|
|
78
90
|
|
|
79
|
-
|
|
80
|
-
`useCrudAddEditScreen()` for routed screens.
|
|
81
|
-
- `useCrudList()`, `useCrudView()`, and `useCrudAddEdit()` for routed CRUD
|
|
82
|
-
behavior.
|
|
83
|
-
- `useList()`, `useView()`, `useAddEdit()`, `useCommand()`, and
|
|
84
|
-
`useEndpointResource()` for non-standard contracts.
|
|
91
|
+
With `json-rest-schema` 1.0.17, temporal resource values are strings:
|
|
85
92
|
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
- `date`: `YYYY-MM-DD`
|
|
94
|
+
- `time`: offset-free `HH:MM[:SS[.fraction]]`
|
|
95
|
+
- `dateTime`: RFC 3339 with seconds and `Z` or a numeric offset
|
|
96
|
+
|
|
97
|
+
Do not pass JavaScript `Date` objects through resource validation; convert at
|
|
98
|
+
the boundary (normally `toISOString()` for `dateTime`). `timestamp` is removed:
|
|
99
|
+
after checking the existing unit, use `epochMilliseconds` or `epochSeconds`.
|
|
100
|
+
Honor `temporalPrecision` without silently truncating fractions. Generated CRUD
|
|
101
|
+
serializes supported database temporal output; custom repositories must return
|
|
102
|
+
strict strings and write ISO/RFC 3339 strings themselves. There is no compatibility alias.
|
|
88
103
|
|
|
89
104
|
## Migration ownership
|
|
90
105
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
later schema change as a new immutable additive migration owned by the
|
|
94
|
-
app-local package:
|
|
106
|
+
Never compete with or alter a generator-owned baseline migration. Later schema
|
|
107
|
+
changes are immutable additive migrations owned by the app-local package:
|
|
95
108
|
|
|
96
109
|
```bash
|
|
97
|
-
npx jskit create migration
|
|
98
|
-
|
|
99
|
-
--id <migration-id>
|
|
100
|
-
npx jskit migrations package <package-id>
|
|
110
|
+
npx --no-install jskit create migration --package <package-id> --id <id>
|
|
111
|
+
npx --no-install jskit migrations package <package-id>
|
|
101
112
|
npm run db:migrate
|
|
102
113
|
```
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
`.jskit/
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Before sign-off, rebuild the full migration chain in a fresh disposable
|
|
110
|
-
database, compare the recreated schema with the intended schema, test relevant
|
|
111
|
-
ownership boundaries, run JSKIT Doctor, and run the project verifier.
|
|
115
|
+
An exceptional persistence lane requires explicit developer approval recorded
|
|
116
|
+
in `.jskit/WORKBOARD.md` and `.jskit/table-ownership.json`, plus
|
|
117
|
+
`.jskit/APP_BLUEPRINT.md` when architectural. Before sign-off, rebuild from
|
|
118
|
+
zero in a fresh disposable database, compare schema, test ownership boundaries,
|
|
119
|
+
run Doctor, and run the verifier.
|
|
@@ -1,73 +1,67 @@
|
|
|
1
1
|
# UI operations
|
|
2
2
|
|
|
3
|
-
Read this
|
|
4
|
-
|
|
3
|
+
Read this for routes, pages, surfaces, placements, responsive UI, and browser
|
|
4
|
+
verification.
|
|
5
5
|
|
|
6
6
|
## Pages, surfaces, and placements
|
|
7
7
|
|
|
8
|
-
Take the
|
|
9
|
-
|
|
10
|
-
placement visibility, and often ownership.
|
|
11
|
-
|
|
12
|
-
For a normal app-owned non-CRUD page, first inspect the generator and semantic
|
|
13
|
-
placements, then generate the page:
|
|
8
|
+
Take the surface from the request/app authority; it controls routes, access,
|
|
9
|
+
placement visibility, and often ownership. For a normal non-CRUD page:
|
|
14
10
|
|
|
15
11
|
```bash
|
|
16
|
-
npx jskit show ui-generator --details
|
|
17
|
-
npx jskit list-placements
|
|
18
|
-
npx jskit generate ui-generator page <route-file> --name <name>
|
|
12
|
+
npx --no-install jskit show ui-generator --details
|
|
13
|
+
npx --no-install jskit list-placements
|
|
14
|
+
npx --no-install jskit generate ui-generator page <route-file> --name <name>
|
|
19
15
|
```
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
Choose the truthful `--navigation-role`. Override with semantic
|
|
18
|
+
`--link-placement <area.slot>` when needed; use concrete placements only for
|
|
19
|
+
diagnosis. Let the generator create the route and placement before adapting
|
|
20
|
+
app-owned output. State why before hand-writing a normal page.
|
|
21
|
+
|
|
22
|
+
## Managed app-owned files
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
“App-owned” means customizable, not disposable while its package is installed.
|
|
25
|
+
Never delete or rename a path recorded in `.jskit/lock.json`; adapt managed
|
|
26
|
+
infrastructure tests in place. When replacing a starter route, update its smoke
|
|
27
|
+
test to the new canonical route instead of deleting baseline browser coverage.
|
|
28
|
+
Doctor must continue to report a missing managed test.
|
|
31
29
|
|
|
32
30
|
## Screen behavior
|
|
33
31
|
|
|
34
|
-
- Keep
|
|
35
|
-
48 px
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
- Use compact searchable cards and medium/expanded tables for generated CRUD
|
|
39
|
-
lists where appropriate.
|
|
32
|
+
- Keep screens phone/task-first with drawer-independent primary actions and
|
|
33
|
+
48 px targets. Use a page header and direct `v-sheet`, not nested cards.
|
|
34
|
+
- Provide named loading, empty, error, permission, and retry states. Generated
|
|
35
|
+
lists use searchable compact cards and medium/expanded tables where suitable.
|
|
40
36
|
- Extend shared CRUD screens through slots. For custom sibling/child links,
|
|
41
37
|
resolve current dynamic params with their runtime to an absolute URL/route
|
|
42
38
|
object; never bind its route-template/relative string raw to Vue Router `to`.
|
|
43
|
-
- Use
|
|
44
|
-
|
|
45
|
-
- Keep ordinary read failures local with runtime `loadError` and retry state.
|
|
46
|
-
Use `useCommand()` or `useUiFeedback()` for user-triggered action feedback.
|
|
39
|
+
- Use page-local row-action/filter definitions. Keep read failures local; use
|
|
40
|
+
`useCommand()` or `useUiFeedback()` for user-triggered action feedback.
|
|
47
41
|
|
|
48
|
-
##
|
|
42
|
+
## Adaptive shell drawer
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
Use Vuetify Material navigation. Compact close dismisses the temporary drawer.
|
|
45
|
+
Wider layouts default to `desktopDrawerClosedMode="rail"`, retaining primary
|
|
46
|
+
navigation as a rail. Use `desktopDrawerClosedMode="hidden"` only when another
|
|
47
|
+
discoverable navigation affordance exists. Do not create a second drawer/menu
|
|
48
|
+
registry or imitate the rail with CSS.
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
URL, server lifecycle, and storage state. When `PLAYWRIGHT_BASE_URL` is set,
|
|
57
|
-
do not start another server. When
|
|
58
|
-
`VIBE64_PLAYWRIGHT_STORAGE_STATE` is supplied, do not print, commit, or retain
|
|
59
|
-
it and do not use local login bypasses. Do not install a browser when the
|
|
60
|
-
environment supplies a managed runner.
|
|
50
|
+
## Browser verification
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
52
|
+
Exercise user-facing changes with Playwright at compact, medium, and expanded
|
|
53
|
+
widths. Check overflow, clipped text, duplicate navigation, route placement,
|
|
54
|
+
actions, and target sizes. Use relative URLs; shared JSKIT config owns base URL,
|
|
55
|
+
server, and storage state. With `PLAYWRIGHT_BASE_URL`, start no server. Never
|
|
56
|
+
print/commit `VIBE64_PLAYWRIGHT_STORAGE_STATE`, use a local bypass with it, or
|
|
57
|
+
install a browser when a managed runner supplies one.
|
|
66
58
|
|
|
67
|
-
|
|
59
|
+
For explicitly enabled direct-local auth, use `loginAsExistingUser()` from
|
|
60
|
+
`@jskit-ai/auth-web/test/playwright`; never expose its secret to browser code,
|
|
61
|
+
URLs, or client env. Record a successful supported run with:
|
|
68
62
|
|
|
69
63
|
```bash
|
|
70
|
-
npx jskit app verify-ui \
|
|
64
|
+
npx --no-install jskit app verify-ui \
|
|
71
65
|
--command "<exact successful Playwright command>" \
|
|
72
66
|
--feature "<changed behavior>" \
|
|
73
67
|
--auth-mode <dev-auth-login-as|session-bootstrap>
|