@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,205 +2,69 @@
2
2
 
3
3
  ---
4
4
  title: Quickstart
5
- description: The fastest path to a real JSKIT app, plus the first page-extension patterns you will usually need.
5
+ description: Create a real JSKIT app through an agent conversation, source patterns, and framework APIs.
6
6
  ---
7
7
 
8
8
  # Quickstart
9
9
 
10
- This chapter is the fastest reproducible path to a real JSKIT app.
10
+ This is the normal AI-first path to a JSKIT application.
11
11
 
12
- The base flow below gives you:
13
-
14
- - personal workspaces
15
- - users
16
- - console
17
- - MySQL
18
- - local auth with no external auth service
19
- - one `admin` assistant configured from `console`
20
-
21
- It also shows the first page-extension moves most apps need:
22
-
23
- - add two workspace settings pages
24
- - make one of them the default landing page
25
- - add a page to the admin cog
26
- - add a normal left-menu page
27
- - inspect placement destinations and understand why some links are inferred automatically
28
-
29
- ## Step 1: Create the app
30
-
31
- Set these values first:
32
-
33
- ```bash
34
- OPENAI_API_KEY=...
35
- DB_HOST=127.0.0.1
36
- DB_PORT=3306
37
- DB_NAME=testapp
38
- DB_USER=...
39
- DB_PASSWORD=...
40
- ```
41
-
42
- Before continuing, make sure the MySQL database already exists and that the chosen `DB_USER` / `DB_PASSWORD` can connect to it. If the database does not exist yet, create it first or use a local MySQL account with enough privileges to create it before the runtime install step.
43
-
44
- Then run the exact sequence below:
12
+ ## Initialize the project conversation
45
13
 
46
14
  ```bash
47
- npx @jskit-ai/create-app testapp --tenancy-mode personal
48
- cd testapp
49
- npm install
50
-
51
- npx jskit add package auth-provider-local-core
52
- npx jskit add package auth-web
53
-
54
- npx jskit add package database-runtime-mysql \
55
- --db-host "$DB_HOST" \
56
- --db-port "$DB_PORT" \
57
- --db-name "$DB_NAME" \
58
- --db-user "$DB_USER" \
59
- --db-password "$DB_PASSWORD"
60
-
61
- npx jskit add package users-web
62
- npx jskit add package console-web
63
- npx jskit add package workspaces-core
64
- npx jskit add package workspaces-web
65
-
66
- npx jskit generate assistant setup \
67
- --surface admin \
68
- --settings-surface console \
69
- --config-scope global \
70
- --ai-provider openai \
71
- --ai-api-key "$OPENAI_API_KEY"
72
-
73
- npx jskit generate assistant page \
74
- w/[workspaceSlug]/admin/assistant/index.vue \
75
- --name "Assistant"
76
-
77
- npx jskit generate assistant settings-page \
78
- console/settings/admin-assistant/index.vue \
79
- --surface admin \
80
- --name "Admin Assistant"
81
-
82
- npm run db:migrate
15
+ mkdir exampleapp
16
+ cd exampleapp
17
+ git init -b main
83
18
  ```
84
19
 
85
- Keep authentication deliberately basic while the product is still taking shape. Start with the local provider and `auth-web`, build the app's core workflows, then add Supabase, OAuth, OTP, provider linking, app-user projection, or workspace/account complexity when the product actually needs those features.
86
-
87
- At this point you have:
20
+ Ask your agent to read the installed JSKIT skill, then describe the product in
21
+ normal language. The opening conversation should make the product direction
22
+ and any material technology choice clear. Explicitly choose JSKIT and any
23
+ database integration you actually need. JSKIT does not ask the same questions
24
+ again through a framework questionnaire.
88
25
 
89
- - a workspace-enabled app with `tenancyMode = "personal"`
90
- - an `admin` assistant at `/w/[workspaceSlug]/admin/assistant`
91
- - an assistant settings page at `/console/settings/admin-assistant`
26
+ ## Select an application foundation
92
27
 
93
- ## Step 2: Add two workspace settings pages
28
+ The installed JSKIT skill and generated pattern index expose two initial
29
+ foundations:
94
30
 
95
- Generate two child pages under the workspace settings host:
31
+ - `app/shell-foundation` for the normal responsive application shell
32
+ - `app/minimal-foundation` for an intentionally smaller foundation
96
33
 
97
- ```bash
98
- npx jskit generate ui-generator page \
99
- w/[workspaceSlug]/admin/workspace/settings/billing/index.vue \
100
- --name "Billing"
101
-
102
- npx jskit generate ui-generator page \
103
- w/[workspaceSlug]/admin/workspace/settings/branding/index.vue \
104
- --name "Branding"
105
- ```
34
+ The agent reads `PATTERN.md` and its complete `example/` tree. It copies or
35
+ adapts the pattern into this existing repository, preserving `.git` and any
36
+ existing project/agent context. It resolves real file collisions and renames
37
+ the concrete `reading-room` example to match the product.
106
38
 
107
- These commands create:
39
+ No `create-app` command, seed wrapper, force-overwrite flow, template
40
+ interpolation, or operation receipt is involved.
108
41
 
109
- - `src/pages/w/[workspaceSlug]/admin/workspace/settings/billing/index.vue`
110
- - `src/pages/w/[workspaceSlug]/admin/workspace/settings/branding/index.vue`
42
+ ## Plan the first capability closure
111
43
 
112
- They also append matching menu entries into `src/placement.js`.
44
+ Choose only what the first useful version needs. For example, an account-based
45
+ database product may need a local auth provider, auth UI, users, and one
46
+ database runtime. A public single-user tool may need none of those.
113
47
 
114
- ## Step 3: Make one settings page the default
48
+ Inspect package details and patterns before modifying the package graph. Apply
49
+ one coherent dependency plan, then run `npm install` once. Environment values
50
+ come from the selected technology contract. They are not product questions and
51
+ must not be copied into committed source.
115
52
 
116
- Best practice is to make the default child explicit.
53
+ ## Build the first product operation
117
54
 
118
- Edit:
119
-
120
- ```text
121
- src/pages/w/[workspaceSlug]/admin/workspace/settings/index.vue
122
- ```
123
-
124
- and replace its contents with:
125
-
126
- ```vue
127
- <script setup>
128
- import { redirectToChild } from "@jskit-ai/kernel/client/pageRedirects";
129
-
130
- definePage({
131
- redirect: redirectToChild("billing")
132
- });
133
- </script>
134
- ```
135
-
136
- That makes `/w/[workspaceSlug]/admin/workspace/settings` land on `/w/[workspaceSlug]/admin/workspace/settings/billing`.
137
-
138
- Use this explicit redirect pattern instead of trying to infer the default child from placement order or “the first generated page”.
139
-
140
- ## Step 4: Add a page to the admin cog
141
-
142
- First list the available placement destinations:
143
-
144
- ```bash
145
- npx jskit list-placements
146
- ```
55
+ Use the narrow relevant pattern and public APIs. For database CRUD, author an
56
+ immutable migration and a normal shared resource contract; use framework APIs
57
+ for standard mechanics and app code for product-specific behavior. Do not
58
+ invoke a source generator or reconstruct one as prompt options.
147
59
 
148
- In a workspace-enabled app, that output includes the semantic `admin.tools-menu` placement.
60
+ ## Verify
149
61
 
150
- Then generate the page:
62
+ Run focused tests throughout. Before handoff, run:
151
63
 
152
- ```bash
153
- npx jskit generate ui-generator page \
154
- w/[workspaceSlug]/admin/catalogue/index.vue \
155
- --name "Catalogue" \
156
- --link-placement admin.tools-menu
157
- ```
158
-
159
- `--link-placement` is necessary here because this is just a normal `admin` page. It is not a child page under a local route host that already owns a nested outlet.
160
-
161
- ## Step 5: Add a normal left-menu page
162
-
163
- Generate a normal `admin` page without an explicit placement:
164
-
165
- ```bash
166
- npx jskit generate ui-generator page \
167
- w/[workspaceSlug]/admin/reports/index.vue \
168
- --name "Reports"
169
- ```
170
-
171
- Because this page is not under a more specific local host, JSKIT falls back to the app's default shell menu outlet. In practice, that means a normal left-menu entry.
172
-
173
- ## Step 6: Understand the placement "magic"
174
-
175
- The workspace settings pages in Step 2 auto-linked into the settings menu for two reasons:
176
-
177
- 1. The parent host already exposes a concrete outlet:
178
-
179
- ```vue
180
- <ShellOutlet target="admin-settings:primary-menu" />
181
- ```
182
-
183
- 2. Your generated pages live under that host route:
184
-
185
- ```text
186
- w/[workspaceSlug]/admin/workspace/settings/...
187
- ```
188
-
189
- So JSKIT can infer both:
190
-
191
- - the semantic placement target: `page.section-nav`
192
- - the placement owner: `admin-settings`
193
-
194
- The renderer comes from `src/placementTopology.js`, where `page.section-nav` maps to the concrete `admin-settings:primary-menu` outlet for each layout class.
195
-
196
- That is why the simple settings-page commands do not need `--link-placement`.
197
-
198
- The admin cog example is different. `w/[workspaceSlug]/admin/catalogue/index.vue` is just a normal admin page, so there is no local nested host to infer. That is why you must pass `--link-placement admin.tools-menu` there.
199
-
200
- If you want a little more context than the raw destination list, this is also useful:
201
-
202
- ```bash
203
- npx jskit show @jskit-ai/workspaces-web --details
204
- ```
64
+ - lint and server/client tests
65
+ - the production build
66
+ - a fresh disposable database rebuild when persistence changed
67
+ - focused Playwright at compact, medium, and expanded sizes for UI work
205
68
 
206
- That output shows both the workspace-owned placement outlets and the default entries already targeting them.
69
+ The current source, dependency graph, migrations, tests, and behavior are the
70
+ evidence. A receipt saying that a tool ran is not evidence.
@@ -2,372 +2,53 @@
2
2
 
3
3
  # Users
4
4
 
5
- At the end of the previous chapter, the app had a real database runtime, but it still did not have JSKIT's own persistent users layer. Authentication worked, but signed-in people were still only provider identities from the auth layer.
6
-
7
- This chapter is where that changes. We install `users-web`, run the new migrations, and let JSKIT start treating authenticated people as persistent app users rather than only as auth-provider identities.
8
-
9
- `users-web` sounds like a UI package, but it is actually the point where several layers arrive together:
10
-
11
- - the persistent users/account data model from `users-core`
12
- - the account surface and account settings UI
13
- - the switch from provider-only auth profiles to users-backed auth profile projection
14
-
15
- This is also the first chapter where the difference between "JSKIT wrote migration files into the app" and "Knex applied those files to the database" becomes important in practice.
16
-
17
- ## Installing `users-web`
18
-
19
- From inside `exampleapp`, run:
5
+ Authentication proves an identity. `@jskit-ai/users-core` gives that identity a
6
+ persistent application profile and settings model; `@jskit-ai/users-web`
7
+ provides self-service account UI.
20
8
 
21
9
  ```bash
22
- npx jskit add package users-web
10
+ npm install @jskit-ai/users-web
23
11
  npm run db:migrate
24
12
  ```
25
13
 
26
- The first command adds `users-web`, but the important part is what arrives with it through its dependency chain.
27
-
28
- - `users-web` adds account, profile, and user-specific shell UI
29
- - `users-core` arrives as a dependency and adds the persistent users/account server layer and schema migrations
30
-
31
- `jskit add` installs those runtime packages and their dependencies. `npm run db:migrate` is the separate step that makes the new tables real in MySQL.
32
-
33
- In the normal install flow, JSKIT materializes the managed `users-core` migration files while the package install is being applied. Then `npm run db:migrate` is what actually runs those files against MySQL.
34
-
35
- **Important: Run The Migrations Before Testing Login**
36
-
37
- This is the first chapter where the migration step is not just "nice to have."
38
-
39
- `users-core` writes:
40
-
41
- - the provider-neutral `auth.profile.projector` service binding through its runtime provider
42
- - `config.auth.profileMode = "users"` into `config/server.js`
43
- - real users/account schema migrations into `migrations/`
44
-
45
- That means the app is expected to project authenticated identities into the persistent users-backed profile sync service. If you skip `npm run db:migrate`, the code and routes are installed, but the required tables are still missing.
46
-
47
- So the correct flow is:
48
-
49
- 1. add `users-web`
50
- 2. run `npx jskit migrations sync --check`
51
- 3. run `npm run db:migrate`
52
- 4. only then start the app and sign in
53
-
54
- `jskit add package users-web` already synchronizes package migration files. The distinction still matters:
55
-
56
- - `jskit migrations sync` writes missing immutable package migration files in `migrations/`
57
- - `npm run db:migrate` actually applies pending migrations to MySQL
58
-
59
- ## What `users-web` adds
60
-
61
- This chapter is the real transition from "authentication exists" to "the app knows about users."
62
-
63
- ### Authentication becomes users-backed
64
-
65
- In the database chapter, JSKIT still treated the signed-in person as an auth-provider identity. After installing `users-web`, JSKIT expects to synchronize authenticated users into real JSKIT tables.
66
-
67
- That is the biggest architectural change in this chapter.
68
-
69
- - the selected auth provider still owns the auth identity and session
70
- - JSKIT owns a persistent users/account data model in MySQL
71
-
72
- So after this chapter, a signed-in user is not only "someone the auth provider knows about." They are also a persistent JSKIT-side user with settings and profile state in the app database.
73
-
74
- ### The app gets an authenticated account surface
75
-
76
- The app has an authenticated surface at `/account`.
77
-
78
- This is where the starter account settings UI lives. It already has real sections for:
79
-
80
- - profile
81
- - preferences
82
- - notifications
83
-
84
- Later chapters can extend this account screen with more sections. For example, the multi-homing chapter adds workspace invitation UI through `workspaces-web`, not through `users-web` itself.
85
-
86
- The important point is that this is a real account route, not a placeholder. It is the first app-owned screen that assumes there is a persistent user model behind it.
87
-
88
- ### The shell changes for signed-in users
89
-
90
- Once a user is signed in, the shell becomes noticeably richer.
91
-
92
- - the profile menu gets a `Settings` entry that leads to `/account`
93
- - the home surface gets a small users tools widget in `shell.status`
94
- - the auth bootstrap payload includes persistent user settings instead of only the fallback mirror data
95
-
96
- So this chapter is also the first one where logging in changes more than just "guest vs signed in." It changes what persistent user-facing surfaces the app can expose.
97
-
98
- ## What to look at in the browser
99
-
100
- Start both processes again:
101
-
102
- ```bash
103
- npm run dev
104
- npm run server
105
- ```
106
-
107
- Then sign in through `http://localhost:5173/auth/login`.
108
-
109
- After a successful sign-in, check these concrete differences compared with the previous chapter:
110
-
111
- - the profile menu contains `Settings`
112
- - `shell.status` includes the users tools widget
113
- - `/account` exists and is authenticated
114
-
115
- This is the first chapter where the app starts to feel like it has a real user model behind it.
116
-
117
- ## What `users-web` adds to the app
118
-
119
- The most interesting files are spread across config, migrations, routing, and the app-owned account UI.
120
-
121
- ### `users-core` projects auth identities into app users
122
-
123
- The most important server-side change is the provider-neutral projector binding from `users-core`:
124
-
125
- ```js
126
- if (!app.has("auth.profile.projector")) {
127
- app.singleton("auth.profile.projector", (scope) => scope.make("users.profile.sync.service"));
128
- }
129
- ```
130
-
131
- That one binding explains the deepest change in the chapter.
132
-
133
- Before this chapter, auth could authenticate a user without creating a persistent app-owned user row. After this chapter, auth providers can call `auth.profile.projector.syncIdentityProfile(...)` and get back a persistent users-backed profile.
134
-
135
- `users-core` also selects users-backed Supabase profile projection:
136
-
137
- ```js
138
- config.auth ||= {};
139
- config.auth.profileMode = "users";
140
- ```
141
-
142
- The local provider uses the token directly. The Supabase provider also understands `config.auth.profileMode = "users"` and resolves the same users-backed sync service. In both cases, this only works because `users-core` installs the required repositories, services, and tables.
143
-
144
- ### `migrations/` stops being mostly empty
145
-
146
- After `users-web`, the app gets real schema files such as:
147
-
148
- ```text
149
- migrations/
150
- 2026..._users-core-generic-initial-schema.cjs
151
- 2026..._users-core-profile-username-schema.cjs
152
- ```
153
-
154
- These files are the first real database schema in the guide.
155
-
156
- The important initial migration creates:
157
-
158
- - `users`
159
- - `user_settings`
160
-
161
- That is why this chapter needs `npm run db:migrate` in a much more serious way than the previous one did.
162
-
163
- ### `config/public.js` gains one new authenticated surface
164
-
165
- After the install, `config/public.js` grows one important surface definition:
166
-
167
- ```js
168
- config.surfaceDefinitions.account = {
169
- id: "account",
170
- label: "Account",
171
- pagesRoot: "account",
172
- enabled: true,
173
- requiresAuth: true,
174
- requiresWorkspace: false,
175
- origin: ""
176
- };
177
- ```
178
-
179
- This chapter keeps the split simple:
180
-
181
- - `account` is the normal authenticated user area
182
- - operator surfaces such as `console` are introduced later, by packages that actually own them
183
-
184
- ### `src/placement.js` grows account entries
185
-
186
- The placement registry also becomes more interesting:
187
-
188
- ```js
189
- addPlacement({
190
- id: "users.profile.menu.settings",
191
- target: "auth.profile-menu",
192
- kind: "link",
193
- surfaces: ["*"],
194
- order: 500,
195
- props: {
196
- label: "Settings",
197
- to: "/account"
198
- },
199
- when: ({ auth }) => Boolean(auth?.authenticated)
200
- });
201
- ```
202
-
203
- This chapter is the first one where one package install adds meaningful authenticated shell entries and a real account surface.
204
-
205
- ### `src/pages/account/index.vue` is a real authenticated route
206
-
207
- The account route itself is very small:
208
-
209
- ```vue
210
- <route lang="json">
211
- {
212
- "meta": {
213
- "guard": {
214
- "policy": "authenticated"
215
- }
216
- }
217
- }
218
- </route>
219
-
220
- <template>
221
- <AccountSettingsClientElement />
222
- </template>
223
-
224
- <script setup>
225
- import AccountSettingsClientElement from "@jskit-ai/users-web/client/components/AccountSettingsClientElement";
226
- </script>
227
- ```
228
-
229
- That is a very JSKIT-style file.
230
-
231
- - the route policy is app-owned
232
- - the page wrapper is app-owned
233
- - the heavy UI is delegated to a package-owned reusable client element
234
-
235
- So the route is simple, but it is already a real authenticated account screen rather than a placeholder card.
236
-
237
- ### The account screen itself is scaffolded app-owned UI
238
-
239
- The account page is backed by:
240
-
241
- ```text
242
- src/components/account/settings/
243
- AccountSettingsProfileSection.vue
244
- AccountSettingsPreferencesSection.vue
245
- AccountSettingsNotificationsSection.vue
246
- ```
247
-
248
- Those three section components stay app-owned so you can reshape the actual UI freely.
249
-
250
- The host itself lives in `users-web` and resolves every account section through the semantic `settings.sections` placement with owner `account-settings`, including the default `profile`, `preferences`, and `notifications` entries.
251
-
252
- So the screen follows the same rule as the rest of JSKIT UI: sections are added by placement rather than being hardcoded into an app-owned host component.
253
-
254
- That is worth noticing because this is a higher level of scaffolding:
255
-
256
- - earlier chapters mostly introduced shells and routes
257
- - this chapter introduces app-owned leaf section UI while the generic section host stays in the package
258
-
259
- ## Under the hood
260
-
261
- ### Why auth uses the users layer
262
-
263
- In the previous chapter, auth did not have a users-backed projector. The core logic in `registerUsersCore()` looks like this:
264
-
265
- ```js
266
- app.singleton("users.profile.sync.service", (scope) => {
267
- return createAuthProfileSyncService({
268
- userProfilesRepository: scope.make("internal.repository.user-profiles"),
269
- userSettingsRepository: scope.make("internal.repository.user-settings"),
270
- lifecycleContributors: resolveProfileSyncLifecycleContributors(scope)
271
- });
272
- });
273
-
274
- if (!app.has("auth.profile.projector")) {
275
- app.singleton("auth.profile.projector", (scope) => scope.make("users.profile.sync.service"));
276
- }
277
- ```
278
-
279
- The important part is concrete.
280
-
281
- After `users-web`:
282
-
283
- - `users-core` supplies `users.profile.sync.service`
284
- - `users-core` aliases that service as `auth.profile.projector`
285
- - the migrations supply the required tables
286
-
287
- So auth has everything it needs to stop returning only provider-owned profile data and start using the persistent users-backed profile.
288
-
289
- That is the true point of this chapter. The app is not just authenticated. It has a real users layer.
290
-
291
- ### `users-core` also owns the profile-sync lifecycle registry
292
-
293
- There is one more seam worth noticing here because later packages depend on it.
294
-
295
- The important thing to understand is that the public extension API is:
296
-
297
- ```js
298
- registerProfileSyncLifecycleContributor(...)
299
- ```
300
-
301
- That is the function another server package uses when it wants to run logic after JSKIT has created or synchronized a user record.
302
-
303
- If you were writing another server package and wanted to run some logic every time a JSKIT user is synchronized, you would register a contributor during package boot:
304
-
305
- ```js
306
- import { registerProfileSyncLifecycleContributor } from "@jskit-ai/users-core/server/profileSyncLifecycleContributorRegistry";
307
-
308
- function registerExampleCore(app) {
309
- registerProfileSyncLifecycleContributor(app, "example.core.profileSyncLogger", () => {
310
- return {
311
- contributorId: "example.core.profileSyncLogger",
312
- order: 0,
313
- async afterIdentityProfileSynced({ profile, created } = {}) {
314
- if (!profile) {
315
- return;
316
- }
317
-
318
- if (created) {
319
- console.log("Created JSKIT user:", profile.id, profile.email);
320
- return;
321
- }
322
-
323
- console.log("Synchronized existing JSKIT user:", profile.id, profile.email);
324
- }
325
- };
326
- });
327
- }
328
- ```
329
-
330
- That example is deliberately simple, but it shows the real usage pattern:
331
-
332
- - import `registerProfileSyncLifecycleContributor(...)`
333
- - call it from your package's server registration code
334
- - implement `afterIdentityProfileSynced(...)`
335
- - use `created` to tell "brand-new user" apart from "existing user synchronized again"
336
-
337
- In a real package, the same seam is useful for things like:
338
-
339
- - provisioning related rows when a user is created
340
- - seeding package-owned settings
341
- - writing audit events
342
- - attaching app-owned resources to the new user
343
-
344
- This runs on the server, inside the same overall sync flow. So if your contributor throws, the sync fails too. That is intentional: the seam is for real lifecycle work, not best-effort UI decoration.
14
+ The installed graph supplies the required users runtime, storage, uploads,
15
+ database, HTTP, and auth integration. The application must already have one
16
+ database driver and one auth provider selected.
345
17
 
346
- Under the hood, `users-core` wires those contributors into the users-backed profile sync service. `registerUsersCore()` resolves the registered contributors when it builds `users.profile.sync.service`, and then `authProfileSyncService.syncIdentityProfile()` runs them after the user row and settings row have been synchronized.
18
+ Package-owned user migrations are discovered directly from the installed
19
+ graph. `npm run db:migrate` is the application-owned Knex command that applies
20
+ them.
347
21
 
348
- - `users-core` owns the tagged registry and the execution point
349
- - auth still only calls one service: `users.profile.sync.service`
350
- - other packages extend the post-sync lifecycle by registering contributors
22
+ ## Self-service accounts
351
23
 
352
- The next chapter uses exactly that pattern. `workspaces-core` registers a contributor so the workspace layer can react when a new user enters the system.
24
+ Use the `users/account-settings` pattern for profile, preference, and
25
+ notification sections. Decide which fields are editable and which operations
26
+ require reauthentication.
353
27
 
354
- Choose `config.tenancyMode` before adding `users-core`. The generator uses that
355
- application decision to create the correct app-owned users package shape.
28
+ Use the framework account settings elements and command composables rather than
29
+ new page-local request clients. Cached query data must hydrate editable fields
30
+ immediately; clearing a value must send the clear operation rather than omit the
31
+ field.
356
32
 
357
- ## Summary
33
+ Loading uses layout-stable skeletons. Mutation errors use a toast, not an
34
+ in-page banner that moves the form.
358
35
 
359
- This chapter is where the app stopped treating signed-in people as only auth-provider identities and started treating them as real JSKIT users.
36
+ ## User administration
360
37
 
361
- - `users-core` installed the persistent users/account schema and server layer
362
- - `users-web` installed the first real account surface and account settings UI
363
- - auth switched from provider-only profile data to the users-backed projection flow
38
+ Use `users/user-administration-server` only when the product needs global or
39
+ workspace-scoped administration beyond self-service settings. It demonstrates
40
+ an app-owned feature package built with `defineCrudJsonApiFeature()` while
41
+ keeping profile persistence in `users-core`.
364
42
 
365
- That is why this chapter feels bigger than a normal page install. It changes both the browser experience and the server-side meaning of "a signed-in user."
43
+ Do not expose password hashes, provider credentials, or session data through a
44
+ user resource. Apply permission and workspace scope before repository access so
45
+ record existence is not leaked.
366
46
 
367
- At the end of this chapter, the app has:
47
+ ## Verification
368
48
 
369
- - real JSKIT-side `users` and `user_settings` tables
370
- - a real authenticated `/account` surface
371
- - a shell that can expose user settings and account tools
49
+ Test profile creation from an authenticated identity, read/update/clear flows,
50
+ warm-cache navigation, uploads when enabled, forbidden administration, missing
51
+ records, pagination, and workspace isolation where relevant.
372
52
 
373
- The next chapter adds a different kind of surface: not a personal account area, but a privileged operator console.
53
+ Do not copy users-core tables or services into the application. Do not add
54
+ field questionnaires, generated-file markers, migration copies, or receipts.