@jskit-ai/agent-docs 0.1.1

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 (73) hide show
  1. package/DISTR_AGENT.md +25 -0
  2. package/guide/agent/app-extras/assistant.md +636 -0
  3. package/guide/agent/app-extras/realtime.md +223 -0
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +643 -0
  5. package/guide/agent/app-setup/authentication.md +948 -0
  6. package/guide/agent/app-setup/console.md +316 -0
  7. package/guide/agent/app-setup/database-layer.md +775 -0
  8. package/guide/agent/app-setup/initial-scaffolding.md +714 -0
  9. package/guide/agent/app-setup/multi-homing.md +655 -0
  10. package/guide/agent/app-setup/users.md +355 -0
  11. package/guide/agent/app-setup/working-with-the-jskit-cli.md +983 -0
  12. package/guide/agent/generators/advanced-cruds.md +923 -0
  13. package/guide/agent/generators/crud-generators.md +556 -0
  14. package/guide/agent/generators/intro.md +63 -0
  15. package/guide/agent/generators/ui-generators.md +648 -0
  16. package/guide/agent/index.md +39 -0
  17. package/guide/human/app-extras/assistant.md +695 -0
  18. package/guide/human/app-extras/realtime.md +270 -0
  19. package/guide/human/app-setup/a-more-interesting-shell.md +734 -0
  20. package/guide/human/app-setup/authentication.md +963 -0
  21. package/guide/human/app-setup/console.md +352 -0
  22. package/guide/human/app-setup/database-layer.md +822 -0
  23. package/guide/human/app-setup/initial-scaffolding.md +738 -0
  24. package/guide/human/app-setup/multi-homing.md +795 -0
  25. package/guide/human/app-setup/users.md +404 -0
  26. package/guide/human/app-setup/working-with-the-jskit-cli.md +997 -0
  27. package/guide/human/generators/advanced-cruds.md +923 -0
  28. package/guide/human/generators/crud-generators.md +556 -0
  29. package/guide/human/generators/intro.md +109 -0
  30. package/guide/human/generators/ui-generators.md +665 -0
  31. package/guide/human/index.md +39 -0
  32. package/package.json +28 -0
  33. package/reference/autogen/KERNEL_MAP.md +536 -0
  34. package/reference/autogen/README.md +44 -0
  35. package/reference/autogen/packages/agent-docs.md +13 -0
  36. package/reference/autogen/packages/assistant-core.md +310 -0
  37. package/reference/autogen/packages/assistant-runtime.md +219 -0
  38. package/reference/autogen/packages/assistant.md +73 -0
  39. package/reference/autogen/packages/auth-core.md +352 -0
  40. package/reference/autogen/packages/auth-provider-supabase-core.md +223 -0
  41. package/reference/autogen/packages/auth-web.md +267 -0
  42. package/reference/autogen/packages/console-core.md +116 -0
  43. package/reference/autogen/packages/console-web.md +37 -0
  44. package/reference/autogen/packages/crud-core.md +283 -0
  45. package/reference/autogen/packages/crud-server-generator.md +220 -0
  46. package/reference/autogen/packages/crud-ui-generator.md +154 -0
  47. package/reference/autogen/packages/database-runtime-mysql.md +61 -0
  48. package/reference/autogen/packages/database-runtime-postgres.md +39 -0
  49. package/reference/autogen/packages/database-runtime.md +216 -0
  50. package/reference/autogen/packages/http-runtime.md +213 -0
  51. package/reference/autogen/packages/kernel.md +1350 -0
  52. package/reference/autogen/packages/realtime.md +95 -0
  53. package/reference/autogen/packages/shell-web.md +349 -0
  54. package/reference/autogen/packages/storage-runtime.md +39 -0
  55. package/reference/autogen/packages/ui-generator.md +101 -0
  56. package/reference/autogen/packages/uploads-image-web.md +76 -0
  57. package/reference/autogen/packages/uploads-runtime.md +85 -0
  58. package/reference/autogen/packages/users-core.md +307 -0
  59. package/reference/autogen/packages/users-web.md +473 -0
  60. package/reference/autogen/packages/workspaces-core.md +415 -0
  61. package/reference/autogen/packages/workspaces-web.md +372 -0
  62. package/reference/autogen/tooling/config-eslint.md +52 -0
  63. package/reference/autogen/tooling/create-app.md +194 -0
  64. package/reference/autogen/tooling/jskit-catalog.md +27 -0
  65. package/reference/autogen/tooling/jskit-cli.md +624 -0
  66. package/reference/autogen/tooling/test-support.md +27 -0
  67. package/reference/autogen/tooling/testUtils.md +31 -0
  68. package/templates/APP_BLUEPRINT.md +57 -0
  69. package/workflow/app-state.md +33 -0
  70. package/workflow/bootstrap.md +24 -0
  71. package/workflow/feature-delivery.md +21 -0
  72. package/workflow/review.md +22 -0
  73. package/workflow/scoping.md +26 -0
@@ -0,0 +1,556 @@
1
+ <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/crud-generators.md`. Do not edit manually. -->
2
+
3
+ # CRUD Generators
4
+
5
+ CRUD generation in JSKIT is really one workflow split across two generator packages:
6
+
7
+ - `crud-server-generator` creates the app-local server/resource package
8
+ - `crud-ui-generator` creates the route tree that uses that shared resource contract
9
+
10
+ So the real order is always:
11
+
12
+ 1. create a real table
13
+ 2. scaffold the server package around it
14
+ 3. scaffold the UI around the generated resource file
15
+
16
+ This chapter uses three examples, in increasing complexity:
17
+
18
+ - `contacts`: the baseline full CRUD walkthrough
19
+ - `addresses`: a child CRUD with its own routed list page
20
+ - `comments`: a child CRUD that lives inside the parent page, with only the child routes being routed
21
+
22
+ The examples assume the guide app already has the database and workspace/admin setup from the earlier chapters. That is why the route roots below live under `w/[workspaceSlug]/admin/...`.
23
+
24
+ This is the workflow chapter.
25
+
26
+ It is meant to answer:
27
+
28
+ - which generator do I run first?
29
+ - what order do the server and UI steps go in?
30
+ - what shape of CRUD should I generate for this feature?
31
+
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
+
34
+ ## The two generator packages
35
+
36
+ ### `crud-server-generator` `@jskit-ai/crud-server-generator` `(0.1.47)`
37
+
38
+ This is the server-side half.
39
+
40
+ It introspects a real table and writes an app-local package with things like:
41
+
42
+ - repository logic
43
+ - service logic
44
+ - route registration
45
+ - action definitions
46
+ - the shared resource module that describes the CRUD contract
47
+
48
+ The main subcommand is:
49
+
50
+ - `scaffold`
51
+
52
+ There is also:
53
+
54
+ - `scaffold-field`
55
+
56
+ which is for patching one extra field into an already-generated resource module after a schema change.
57
+
58
+ ### `crud-ui-generator` `@jskit-ai/crud-ui-generator` `(0.1.22)`
59
+
60
+ This is the UI half.
61
+
62
+ It reads the generated shared resource module and creates app-owned pages under an explicit route root relative to `src/pages/`.
63
+
64
+ The main subcommand is:
65
+
66
+ - `crud`
67
+
68
+ That command can generate any combination of:
69
+
70
+ - `list`
71
+ - `view`
72
+ - `new`
73
+ - `edit`
74
+
75
+ That flexibility is what makes the later `comments` example possible.
76
+
77
+ ## Understanding ownership filters
78
+
79
+ `--ownership-filter` is one of the most important CRUD generator options.
80
+
81
+ It is not just "one more flag." It tells JSKIT what kind of ownership the generated CRUD assumes:
82
+
83
+ - whether records are shared or owner-scoped
84
+ - which owner columns the CRUD expects
85
+ - what request context the generated routes and repository use to filter records
86
+
87
+ In plain English, it answers:
88
+
89
+ - who should be able to see these rows?
90
+ - what kind of owner does each row belong to?
91
+
92
+ The supported values are:
93
+
94
+ | Value | Plain meaning | Typical owner columns |
95
+ | --- | --- | --- |
96
+ | `auto` | infer ownership from the real table during generation | inferred from table shape |
97
+ | `public` | no owner scoping | no `workspace_id` or `user_id` required |
98
+ | `user` | rows belong to one user | `user_id` |
99
+ | `workspace` | rows belong to one workspace | `workspace_id` |
100
+ | `workspace_user` | rows belong to one workspace and one user together | `workspace_id` and `user_id` |
101
+
102
+ ### What each value means
103
+
104
+ #### `public`
105
+
106
+ Choose `public` when the same records should be visible across the app, subject only to the usual route/action permissions.
107
+
108
+ This is the right mental model for things like:
109
+
110
+ - global lookup tables
111
+ - app-wide reference data
112
+ - shared configuration records that are not owned by one user or one workspace
113
+
114
+ A `public` CRUD does **not** expect owner scoping columns.
115
+
116
+ #### `user`
117
+
118
+ Choose `user` when each record belongs to one user, regardless of which app surface is showing it.
119
+
120
+ This is the right mental model for things like:
121
+
122
+ - my own saved items
123
+ - my saved views
124
+ - my personal preferences records when they are stored as CRUD rows
125
+
126
+ The important owner column is:
127
+
128
+ - `user_id`
129
+
130
+ #### `workspace`
131
+
132
+ Choose `workspace` when records belong to the workspace as a whole.
133
+
134
+ This is the most common choice for workspace-admin CRUDs such as:
135
+
136
+ - contacts
137
+ - appointments
138
+ - products
139
+ - workspace-wide CRM records
140
+
141
+ The important owner column is:
142
+
143
+ - `workspace_id`
144
+
145
+ This is why the chapter's `contacts` example uses `workspace`: the records belong to the workspace, not to one specific member inside it.
146
+
147
+ #### `workspace_user`
148
+
149
+ Choose `workspace_user` when a record belongs to a workspace **and** to a specific user within that workspace.
150
+
151
+ This is the right mental model for things like:
152
+
153
+ - personal notes inside a workspace
154
+ - per-user workspace drafts
155
+ - user-owned workspace artifacts that should not be visible to every workspace member
156
+
157
+ The important owner columns are:
158
+
159
+ - `workspace_id`
160
+ - `user_id`
161
+
162
+ This is stricter than plain `workspace`. The row is not only "inside this workspace." It is "inside this workspace, for this user."
163
+
164
+ #### `auto`
165
+
166
+ `auto` is not a runtime mode. It is a **generation-time inference**.
167
+
168
+ When you scaffold against a real table, the generator inspects the table columns and resolves `auto` like this:
169
+
170
+ - `workspace_id` and `user_id` present -> `workspace_user`
171
+ - `workspace_id` only -> `workspace`
172
+ - `user_id` only -> `user`
173
+ - neither present -> `public`
174
+
175
+ So `auto` is useful when the table already exists and its ownership columns already tell the truth.
176
+
177
+ If you already know the intended ownership model and want the command to fail when the table does not match it, choose the explicit value instead of `auto`.
178
+
179
+ ### Which one should I choose?
180
+
181
+ Use this rule of thumb:
182
+
183
+ - choose `public` for shared reference/config data
184
+ - choose `user` for "my own" records
185
+ - choose `workspace` for workspace-wide business data
186
+ - choose `workspace_user` for personal records that still live inside a workspace
187
+ - choose `auto` when you are scaffolding from an existing table and want JSKIT to infer ownership from the owner columns already present
188
+
189
+ Another useful way to think about it is this:
190
+
191
+ - if two different users in the same workspace should normally see the same row, that is probably `workspace`
192
+ - if they should **not** normally see the same row, that is probably `workspace_user`
193
+ - if the row is not workspace-specific at all, it is probably `public` or `user`
194
+
195
+ ### One more important constraint
196
+
197
+ Ownership also has to make sense for the target surface.
198
+
199
+ In practice:
200
+
201
+ - `workspace` and `workspace_user` belong on workspace-enabled surfaces
202
+ - `public` and `user` can live on non-workspace surfaces too
203
+
204
+ So if you are generating under a route like:
205
+
206
+ ```text
207
+ w/[workspaceSlug]/admin/...
208
+ ```
209
+
210
+ then `workspace` is usually the normal default. If you are generating a CRUD for a global operator or account area, `public` or `user` may make more sense.
211
+
212
+ ## Example 1: `contacts`
213
+
214
+ This is the baseline pattern. If you understand this example, the rest of the chapter becomes much easier.
215
+
216
+ ### Step 1: create the table first
217
+
218
+ Start with a real table. The server generator reads the database schema; it does not invent it for you.
219
+
220
+ Example:
221
+
222
+ ```sql
223
+ CREATE TABLE contacts (
224
+ id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
225
+ workspace_id BIGINT UNSIGNED NOT NULL,
226
+ full_name VARCHAR(190) NOT NULL,
227
+ email VARCHAR(190) NULL,
228
+ phone VARCHAR(50) NULL,
229
+ notes TEXT NULL,
230
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
231
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
232
+ KEY idx_contacts_workspace_id (workspace_id)
233
+ );
234
+ ```
235
+
236
+ The exact fields will vary by app. What matters for the generator is:
237
+
238
+ - the table already exists
239
+ - the ownership columns match the ownership filter you are going to choose
240
+ - the column names are stable enough to become part of your app's resource contract
241
+
242
+ In this table, `workspace_id` is the important ownership clue. That is why the next step uses:
243
+
244
+ ```bash
245
+ --ownership-filter workspace
246
+ ```
247
+
248
+ This CRUD is not "my contacts." It is "the workspace's contacts."
249
+
250
+ ### Step 2: scaffold the server package
251
+
252
+ Now generate the server-side CRUD package:
253
+
254
+ ```bash
255
+ npx jskit generate crud-server-generator scaffold \
256
+ --namespace contacts \
257
+ --surface admin \
258
+ --ownership-filter workspace \
259
+ --table-name contacts
260
+ ```
261
+
262
+ This creates an app-local package under `packages/contacts/`.
263
+
264
+ The most important file from the UI point of view is:
265
+
266
+ ```text
267
+ packages/contacts/src/shared/contactResource.js
268
+ ```
269
+
270
+ That file is the shared CRUD contract. The UI generator reads it to decide:
271
+
272
+ - which operations exist
273
+ - which fields are readable or writable
274
+ - which relations are exposed
275
+ - how to build the generated pages
276
+
277
+ So even though the server scaffold writes many files, the resource file is the bridge between the server and UI halves.
278
+
279
+ ### Step 3: scaffold the UI
280
+
281
+ Once the resource file exists, generate the UI route tree:
282
+
283
+ ```bash
284
+ npx jskit generate crud-ui-generator crud \
285
+ w/[workspaceSlug]/admin/contacts \
286
+ --resource-file packages/contacts/src/shared/contactResource.js \
287
+ --id-param contactId \
288
+ --display-fields fullName,email,phone
289
+ ```
290
+
291
+ That creates the baseline CRUD route tree:
292
+
293
+ - `w/[workspaceSlug]/admin/contacts/index.vue`
294
+ - `w/[workspaceSlug]/admin/contacts/new.vue`
295
+ - `w/[workspaceSlug]/admin/contacts/[contactId]/index.vue`
296
+ - `w/[workspaceSlug]/admin/contacts/[contactId]/edit.vue`
297
+ - shared `_components` files under the same route root
298
+
299
+ This is the most important mental model in the whole chapter:
300
+
301
+ - `crud-server-generator` creates the reusable CRUD contract and server package
302
+ - `crud-ui-generator` turns that contract into app-owned pages
303
+
304
+ If you want to see exactly what lands in `packages/contacts/`, which files own repository/service/action logic, and how search/filter customization is supposed to work, continue with [Advanced CRUDs](/guide/generators/advanced-cruds) once this baseline flow is clear.
305
+
306
+ ### Why this is the baseline example
307
+
308
+ `contacts` is the cleanest first example because nothing fancy is happening yet:
309
+
310
+ - it has a normal routed list page
311
+ - it has a normal routed view page
312
+ - it has normal `new` and `edit` pages
313
+ - it uses one straightforward resource contract
314
+
315
+ That is the shape to learn first.
316
+
317
+ ## Example 2: `addresses`
318
+
319
+ Now move to a child CRUD with its own URL.
320
+
321
+ This is the right pattern when the child collection deserves its own list page.
322
+
323
+ Example route:
324
+
325
+ ```text
326
+ .../contacts/3/addresses
327
+ ```
328
+
329
+ In the guide app's real route tree, that becomes:
330
+
331
+ ```text
332
+ w/[workspaceSlug]/admin/contacts/[contactId]/addresses
333
+ ```
334
+
335
+ ### Step 1: create the child table
336
+
337
+ Example:
338
+
339
+ ```sql
340
+ CREATE TABLE addresses (
341
+ id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
342
+ workspace_id BIGINT UNSIGNED NOT NULL,
343
+ contact_id BIGINT UNSIGNED NOT NULL,
344
+ label VARCHAR(100) NULL,
345
+ line_1 VARCHAR(190) NOT NULL,
346
+ line_2 VARCHAR(190) NULL,
347
+ suburb VARCHAR(120) NULL,
348
+ state VARCHAR(80) NULL,
349
+ postcode VARCHAR(20) NULL,
350
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
351
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
352
+ KEY idx_addresses_workspace_id (workspace_id),
353
+ KEY idx_addresses_contact_id (contact_id)
354
+ );
355
+ ```
356
+
357
+ The important extra column here is `contact_id`. This is what makes the CRUD a child of a contact instead of a top-level resource.
358
+
359
+ ### Step 2: scaffold the server package
360
+
361
+ ```bash
362
+ npx jskit generate crud-server-generator scaffold \
363
+ --namespace addresses \
364
+ --surface admin \
365
+ --ownership-filter workspace \
366
+ --table-name addresses
367
+ ```
368
+
369
+ ### Step 3: scaffold the UI at the child route root
370
+
371
+ ```bash
372
+ npx jskit generate crud-ui-generator crud \
373
+ w/[workspaceSlug]/admin/contacts/[contactId]/addresses \
374
+ --resource-file packages/addresses/src/shared/addressResource.js \
375
+ --id-param addressId \
376
+ --display-fields label,line1,postcode
377
+ ```
378
+
379
+ That gives you a proper child CRUD with its own list, view, new, and edit pages under the contact route.
380
+
381
+ ### The important refinement: parent title handling
382
+
383
+ This is where nested CRUD starts to feel real.
384
+
385
+ An addresses list page should not show a generic heading like `Addresses`. It should usually show whose addresses these are, for example:
386
+
387
+ - `Jane Smith's addresses`
388
+ - `Acme Pty Ltd's addresses`
389
+
390
+ The awkward case is when there are **no child rows yet**. If the list is empty, you cannot derive the parent title from the first address record.
391
+
392
+ That is why JSKIT has `useCrudListParentTitle()`:
393
+
394
+ ```js
395
+ const parentTitle = useCrudListParentTitle({
396
+ listRuntime: records,
397
+ resource: uiResource,
398
+ recordIdParam: "addressId",
399
+ fallbackLoadError: "Unable to load contact.",
400
+ notFoundMessage: "Contact not found."
401
+ });
402
+ ```
403
+
404
+ That helper does the nice thing automatically:
405
+
406
+ - if the child list already has rows, it derives the parent title from the first child record
407
+ - if the child list is empty, it loads the parent record directly
408
+
409
+ This is exactly the pattern used in the real app codebase for nested CRUD lists like a contact's pets. It avoids the common broken state where an empty child list loses all context about the parent it belongs to.
410
+
411
+ So the `addresses` example is important because it teaches the first truly practical nested-CRUD problem:
412
+
413
+ - the route is child-scoped
414
+ - the data is child-scoped
415
+ - but the page still needs a reliable parent identity even when the child list is empty
416
+
417
+ ## Example 3: `comments` in-page
418
+
419
+ This is the advanced example.
420
+
421
+ Sometimes a child resource is real enough to deserve its own CRUD operations, but **not** important enough to deserve its own full-screen list page.
422
+
423
+ Comments are a good example:
424
+
425
+ - they matter
426
+ - they need persistence
427
+ - they may need `view`, `new`, or `edit` routes
428
+ - but the main screen is still the contact view page
429
+
430
+ So the pattern is:
431
+
432
+ - keep the contact page as the real host
433
+ - render the comments list inside that page
434
+ - route only the child operations underneath it
435
+
436
+ ### Step 1: create the table
437
+
438
+ Example:
439
+
440
+ ```sql
441
+ CREATE TABLE comments (
442
+ id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
443
+ workspace_id BIGINT UNSIGNED NOT NULL,
444
+ contact_id BIGINT UNSIGNED NOT NULL,
445
+ author_user_id BIGINT UNSIGNED NULL,
446
+ body TEXT NOT NULL,
447
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
448
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
449
+ KEY idx_comments_workspace_id (workspace_id),
450
+ KEY idx_comments_contact_id (contact_id)
451
+ );
452
+ ```
453
+
454
+ ### Step 2: scaffold the server package
455
+
456
+ ```bash
457
+ npx jskit generate crud-server-generator scaffold \
458
+ --namespace comments \
459
+ --surface admin \
460
+ --ownership-filter workspace \
461
+ --table-name comments
462
+ ```
463
+
464
+ ### Step 3: make the parent page able to host routed children
465
+
466
+ If the contact view page should stay visible while child comment routes render underneath it, first upgrade it into a routed host:
467
+
468
+ ```bash
469
+ npx jskit generate ui-generator add-subpages \
470
+ w/[workspaceSlug]/admin/contacts/[contactId]/index.vue \
471
+ --title "Contact" \
472
+ --subtitle "View and manage this contact."
473
+ ```
474
+
475
+ That is the point where the comments example deliberately overlaps with the `ui-generator` chapter. This pattern needs both:
476
+
477
+ - CRUD scaffolding for the comments resource
478
+ - a routed host in the parent contact page
479
+
480
+ ### Step 4: generate only the routed child operations
481
+
482
+ Now generate the comments UI without a list page:
483
+
484
+ ```bash
485
+ npx jskit generate crud-ui-generator crud \
486
+ w/[workspaceSlug]/admin/contacts/[contactId]/index/comments \
487
+ --resource-file packages/comments/src/shared/commentResource.js \
488
+ --operations view,new,edit \
489
+ --id-param commentId
490
+ ```
491
+
492
+ This is the key move.
493
+
494
+ By leaving `list` out:
495
+
496
+ - you do **not** generate a standalone comments list page
497
+ - the host contact page stays responsible for showing the comment list
498
+ - the generated child routes still handle things like `new`, `view`, and `edit`
499
+
500
+ ### What the host page does
501
+
502
+ The host page then renders the comment list directly, usually with lower-level CRUD composables such as:
503
+
504
+ - `useCrudList()`
505
+ - `useCrudAddEdit()`
506
+ - `useCrudView()` when needed
507
+
508
+ That is the same general pattern already used in the real app for embedded child records like pet notes: the record list lives inside the main view page, while routed child pages handle the operations that still deserve their own URLs.
509
+
510
+ This pattern is useful when the child records are supporting detail rather than a destination in their own right.
511
+
512
+ That is the real lesson of the `comments` example:
513
+
514
+ - a child CRUD does **not** have to mean "make another full-screen list page"
515
+ - you can keep the parent page as the main experience and route only the child operations that benefit from their own URLs
516
+
517
+ ## When `scaffold-field` matters
518
+
519
+ After the initial scaffold, schema changes are normal.
520
+
521
+ Suppose you add a `preferred_name` column to `contacts`. You do not have to regenerate the whole package just to expose that one new writable field.
522
+
523
+ That is what `scaffold-field` is for:
524
+
525
+ ```bash
526
+ npx jskit generate crud-server-generator scaffold-field \
527
+ preferredName \
528
+ packages/contacts/src/shared/contactResource.js \
529
+ --table-name contacts
530
+ ```
531
+
532
+ Use this when:
533
+
534
+ - the CRUD package already exists
535
+ - the table has changed
536
+ - you want to patch one writable field into the generated resource file
537
+
538
+ It is a maintenance tool, not the first step in the workflow.
539
+
540
+ ## Summary
541
+
542
+ The important thing is not memorizing commands. It is learning the three shapes:
543
+
544
+ - `contacts`: a normal top-level CRUD
545
+ - `addresses`: a child CRUD with its own routed list page
546
+ - `comments`: a child CRUD that lives inside the parent page, with only the child operations routed
547
+
548
+ Once you understand those three shapes, the two generator packages stop feeling like separate tools.
549
+
550
+ They become one workflow:
551
+
552
+ 1. model the table
553
+ 2. scaffold the server/resource package
554
+ 3. scaffold only the UI shape that the feature actually needs
555
+
556
+ The next chapter is [Advanced CRUDs](/guide/generators/advanced-cruds). Read it as the structural follow-on to this one: this chapter teaches how to generate the CRUD, and the next one teaches how to reason about the files you now own.
@@ -0,0 +1,109 @@
1
+ <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/intro.md`. Do not edit manually. -->
2
+
3
+ # Generators
4
+
5
+ By the end of the app-setup chapters, the guide app already has the main structural pieces in place:
6
+
7
+ - a real shell
8
+ - authenticated users
9
+ - a database layer
10
+ - operator tooling
11
+ - workspace-aware routing
12
+
13
+ This section changes focus.
14
+
15
+ Generators are the part of JSKIT that write app-owned files on top of installed runtime packages.
16
+
17
+ That is different from `npx jskit add package ...`:
18
+
19
+ - `add package` installs reusable runtime capability into the app
20
+ - `generate ...` creates local pages, components, placements, and support files that your app owns directly
21
+
22
+ So the normal flow is:
23
+
24
+ 1. install the runtime packages that make the feature possible
25
+ 2. decide the exact app-owned route, component, or package you want
26
+ 3. run `npx jskit generate ...`
27
+ 4. review and keep editing the generated files
28
+
29
+ One important detail: generator packages such as `ui-generator`, `crud-server-generator`, and `crud-ui-generator` are tooling surfaces. You normally do **not** add them to your app with `jskit add package ...`. You use them through the CLI, and they mutate your app-owned files.
30
+
31
+ This intro is also the shared starting point for the rest of the generators section.
32
+
33
+ ## Recap From Previous Chapters
34
+
35
+ To get back to the same starting point used in the later generator chapters, run:
36
+
37
+ ```bash
38
+ SUPABASE_URL=...
39
+ SUPABASE_KEY=...
40
+ DB_HOST=127.0.0.1
41
+ DB_PORT=3306
42
+ DB_NAME=exampleapp
43
+ DB_USER=exampleapp
44
+ DB_PASSWORD=secret
45
+
46
+ npx @jskit-ai/create-app exampleapp --tenancy-mode personal
47
+ cd exampleapp
48
+ npm install
49
+
50
+ npx jskit add package shell-web
51
+ npx jskit add package auth-provider-supabase-core \
52
+ --auth-supabase-url "$SUPABASE_URL" \
53
+ --auth-supabase-publishable-key "$SUPABASE_KEY" \
54
+ --app-public-url "http://localhost:5173"
55
+ npx jskit add bundle auth-base
56
+ npx jskit add package database-runtime-mysql \
57
+ --db-host "$DB_HOST" \
58
+ --db-port "$DB_PORT" \
59
+ --db-name "$DB_NAME" \
60
+ --db-user "$DB_USER" \
61
+ --db-password "$DB_PASSWORD"
62
+ npx jskit add package users-web
63
+ npx jskit add package console-web
64
+ npx jskit add package workspaces-core
65
+ npx jskit add package workspaces-web
66
+ npm install
67
+ npm run db:migrate
68
+ ```
69
+
70
+ If you are already continuing from the earlier guide chapters, you are already in the right place and can skip that setup.
71
+
72
+ That baseline matters because the later generator examples assume:
73
+
74
+ - a shell with placements and routed pages
75
+ - authenticated users and user-owned routes
76
+ - database-backed runtime packages
77
+ - console and workspace surfaces that real generated pages can target
78
+
79
+ ## Current generator families
80
+
81
+ Right now the guide splits generators into two practical groups:
82
+
83
+ - `@jskit-ai/ui-generator` for non-CRUD pages, placed UI, subpage hosts, and generic outlets
84
+ - `@jskit-ai/crud-server-generator` plus `@jskit-ai/crud-ui-generator` for end-to-end CRUD scaffolding
85
+
86
+ For CRUD work, there are also two guide layers on purpose:
87
+
88
+ - [CRUD Generators](/guide/generators/crud-generators) teaches the end-to-end workflow for generating a working CRUD
89
+ - [Advanced CRUDs](/guide/generators/advanced-cruds) explains the generated package anatomy, ownership structure, and the safest places to customize it
90
+
91
+ The intended reading order is:
92
+
93
+ 1. `CRUD Generators`
94
+ 2. `Advanced CRUDs`
95
+
96
+ ## Why generators matter
97
+
98
+ This is one of the main JSKIT ideas:
99
+
100
+ - packages own reusable framework/runtime behavior
101
+ - generators write the app-local files that make that behavior concrete in your app
102
+
103
+ That keeps the runtime reusable without hiding your real app UI behind opaque framework internals.
104
+
105
+ ## Next sections
106
+
107
+ - [UI Generators](/guide/generators/ui-generators) covers the non-CRUD workflow built around `ui-generator`
108
+ - [CRUD Generators](/guide/generators/crud-generators) covers the combined server-and-UI CRUD workflow using `contacts`, nested `addresses`, and in-page `comments`
109
+ - [Advanced CRUDs](/guide/generators/advanced-cruds) is the follow-on chapter after `CRUD Generators`, and goes deeper into the generated CRUD structure, ownership boundaries, and search/filter customization