@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.
- package/DISTR_AGENT.md +25 -0
- package/guide/agent/app-extras/assistant.md +636 -0
- package/guide/agent/app-extras/realtime.md +223 -0
- package/guide/agent/app-setup/a-more-interesting-shell.md +643 -0
- package/guide/agent/app-setup/authentication.md +948 -0
- package/guide/agent/app-setup/console.md +316 -0
- package/guide/agent/app-setup/database-layer.md +775 -0
- package/guide/agent/app-setup/initial-scaffolding.md +714 -0
- package/guide/agent/app-setup/multi-homing.md +655 -0
- package/guide/agent/app-setup/users.md +355 -0
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +983 -0
- package/guide/agent/generators/advanced-cruds.md +923 -0
- package/guide/agent/generators/crud-generators.md +556 -0
- package/guide/agent/generators/intro.md +63 -0
- package/guide/agent/generators/ui-generators.md +648 -0
- package/guide/agent/index.md +39 -0
- package/guide/human/app-extras/assistant.md +695 -0
- package/guide/human/app-extras/realtime.md +270 -0
- package/guide/human/app-setup/a-more-interesting-shell.md +734 -0
- package/guide/human/app-setup/authentication.md +963 -0
- package/guide/human/app-setup/console.md +352 -0
- package/guide/human/app-setup/database-layer.md +822 -0
- package/guide/human/app-setup/initial-scaffolding.md +738 -0
- package/guide/human/app-setup/multi-homing.md +795 -0
- package/guide/human/app-setup/users.md +404 -0
- package/guide/human/app-setup/working-with-the-jskit-cli.md +997 -0
- package/guide/human/generators/advanced-cruds.md +923 -0
- package/guide/human/generators/crud-generators.md +556 -0
- package/guide/human/generators/intro.md +109 -0
- package/guide/human/generators/ui-generators.md +665 -0
- package/guide/human/index.md +39 -0
- package/package.json +28 -0
- package/reference/autogen/KERNEL_MAP.md +536 -0
- package/reference/autogen/README.md +44 -0
- package/reference/autogen/packages/agent-docs.md +13 -0
- package/reference/autogen/packages/assistant-core.md +310 -0
- package/reference/autogen/packages/assistant-runtime.md +219 -0
- package/reference/autogen/packages/assistant.md +73 -0
- package/reference/autogen/packages/auth-core.md +352 -0
- package/reference/autogen/packages/auth-provider-supabase-core.md +223 -0
- package/reference/autogen/packages/auth-web.md +267 -0
- package/reference/autogen/packages/console-core.md +116 -0
- package/reference/autogen/packages/console-web.md +37 -0
- package/reference/autogen/packages/crud-core.md +283 -0
- package/reference/autogen/packages/crud-server-generator.md +220 -0
- package/reference/autogen/packages/crud-ui-generator.md +154 -0
- package/reference/autogen/packages/database-runtime-mysql.md +61 -0
- package/reference/autogen/packages/database-runtime-postgres.md +39 -0
- package/reference/autogen/packages/database-runtime.md +216 -0
- package/reference/autogen/packages/http-runtime.md +213 -0
- package/reference/autogen/packages/kernel.md +1350 -0
- package/reference/autogen/packages/realtime.md +95 -0
- package/reference/autogen/packages/shell-web.md +349 -0
- package/reference/autogen/packages/storage-runtime.md +39 -0
- package/reference/autogen/packages/ui-generator.md +101 -0
- package/reference/autogen/packages/uploads-image-web.md +76 -0
- package/reference/autogen/packages/uploads-runtime.md +85 -0
- package/reference/autogen/packages/users-core.md +307 -0
- package/reference/autogen/packages/users-web.md +473 -0
- package/reference/autogen/packages/workspaces-core.md +415 -0
- package/reference/autogen/packages/workspaces-web.md +372 -0
- package/reference/autogen/tooling/config-eslint.md +52 -0
- package/reference/autogen/tooling/create-app.md +194 -0
- package/reference/autogen/tooling/jskit-catalog.md +27 -0
- package/reference/autogen/tooling/jskit-cli.md +624 -0
- package/reference/autogen/tooling/test-support.md +27 -0
- package/reference/autogen/tooling/testUtils.md +31 -0
- package/templates/APP_BLUEPRINT.md +57 -0
- package/workflow/app-state.md +33 -0
- package/workflow/bootstrap.md +24 -0
- package/workflow/feature-delivery.md +21 -0
- package/workflow/review.md +22 -0
- package/workflow/scoping.md +26 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/users.md`. Do not edit manually. -->
|
|
2
|
+
|
|
3
|
+
# Users
|
|
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 the app-side profile mirror was still only the temporary fallback from the auth chapter.
|
|
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 Supabase 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 standalone auth profile sync to users-backed auth profile sync
|
|
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:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx jskit add package users-web
|
|
23
|
+
npm install
|
|
24
|
+
npm run db:migrate
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The first command adds `users-web`, but the important part is what arrives with it through its dependency chain.
|
|
28
|
+
|
|
29
|
+
- `users-web` adds the account-facing UI and client runtime pieces
|
|
30
|
+
- `users-core` arrives as a dependency and adds the persistent users/account server layer and schema migrations
|
|
31
|
+
|
|
32
|
+
`npm install` downloads those new runtime packages and their dependencies. `npm run db:migrate` is the crucial step that makes the new tables real in MySQL.
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
**Important: Run The Migrations Before Testing Login**
|
|
37
|
+
|
|
38
|
+
This is the first chapter where the migration step is not just "nice to have."
|
|
39
|
+
|
|
40
|
+
`users-core` writes:
|
|
41
|
+
|
|
42
|
+
- `AUTH_PROFILE_MODE=users` into `.env`
|
|
43
|
+
- real users/account schema migrations into `migrations/`
|
|
44
|
+
|
|
45
|
+
That means the app is now expected to use 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 `npm install`
|
|
51
|
+
3. if you need JSKIT to refresh the managed migration files, run `npx jskit migrations changed`
|
|
52
|
+
4. run `npm run db:migrate`
|
|
53
|
+
5. only then start the app and sign in
|
|
54
|
+
|
|
55
|
+
Most of the time, step 3 is not needed because `jskit add package users-web` already wrote the managed migration files. But the distinction still matters:
|
|
56
|
+
|
|
57
|
+
- `jskit migrations changed` writes or refreshes JSKIT-managed migration files in `migrations/`
|
|
58
|
+
- `npm run db:migrate` actually applies pending migrations to MySQL
|
|
59
|
+
|
|
60
|
+
## What changes now
|
|
61
|
+
|
|
62
|
+
This chapter is the real transition from "authentication exists" to "the app knows about users."
|
|
63
|
+
|
|
64
|
+
### Authentication becomes users-backed
|
|
65
|
+
|
|
66
|
+
In the database chapter, JSKIT still used the standalone in-memory profile mirror. After installing `users-web`, that changes. JSKIT now expects to synchronize authenticated users into real JSKIT tables.
|
|
67
|
+
|
|
68
|
+
That is the biggest architectural change in this chapter.
|
|
69
|
+
|
|
70
|
+
- Supabase still owns the real auth identity and session
|
|
71
|
+
- JSKIT now also owns a persistent users/account data model in MySQL
|
|
72
|
+
|
|
73
|
+
So after this chapter, a signed-in user is no longer only "someone Supabase knows about." They are also a persistent JSKIT-side user with settings and profile state in the app database.
|
|
74
|
+
|
|
75
|
+
### The app gets an authenticated account surface
|
|
76
|
+
|
|
77
|
+
The app now has a new authenticated surface at `/account`.
|
|
78
|
+
|
|
79
|
+
This is where the starter account settings UI lives. It already has real sections for:
|
|
80
|
+
|
|
81
|
+
- profile
|
|
82
|
+
- preferences
|
|
83
|
+
- notifications
|
|
84
|
+
|
|
85
|
+
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.
|
|
86
|
+
|
|
87
|
+
The important point is that this is no longer just a placeholder route. It is the first app-owned screen that assumes there is a real persistent user model behind it.
|
|
88
|
+
|
|
89
|
+
### The shell changes for signed-in users
|
|
90
|
+
|
|
91
|
+
Once a user is signed in, the shell becomes noticeably richer.
|
|
92
|
+
|
|
93
|
+
- the profile menu gets a `Settings` entry that leads to `/account`
|
|
94
|
+
- the home surface gets a small users tools widget in the top-right area
|
|
95
|
+
- the auth bootstrap payload now includes persistent user settings instead of only the fallback mirror data
|
|
96
|
+
|
|
97
|
+
So this chapter is also the first one where logging in changes more than just "guest vs signed in." It now changes what persistent user-facing surfaces the app can expose.
|
|
98
|
+
|
|
99
|
+
## What to look at in the browser
|
|
100
|
+
|
|
101
|
+
Start both processes again:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npm run dev
|
|
105
|
+
npm run server
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then sign in through `http://localhost:5173/auth/login`.
|
|
109
|
+
|
|
110
|
+
After a successful sign-in, you should notice three concrete differences compared with the previous chapter:
|
|
111
|
+
|
|
112
|
+
- the profile menu now contains `Settings`
|
|
113
|
+
- the top-right area now also has a small users tools widget
|
|
114
|
+
- `/account` now exists and is authenticated
|
|
115
|
+
|
|
116
|
+
This is the first chapter where the app starts to feel like it has a real user model behind it.
|
|
117
|
+
|
|
118
|
+
## What `users-web` adds to the app
|
|
119
|
+
|
|
120
|
+
The most interesting files now are spread across config, migrations, routing, and the app-owned account UI.
|
|
121
|
+
|
|
122
|
+
### `.env` flips auth into users mode
|
|
123
|
+
|
|
124
|
+
The most important new line in `.env` is:
|
|
125
|
+
|
|
126
|
+
```dotenv
|
|
127
|
+
AUTH_PROFILE_MODE=users
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
That one line explains the deepest change in the chapter.
|
|
131
|
+
|
|
132
|
+
Before this chapter, auth used the standalone fallback profile sync service. After this chapter, auth is told to use the persistent users-backed profile sync flow instead.
|
|
133
|
+
|
|
134
|
+
That only works because `users-core` also installs the required repositories, services, and tables.
|
|
135
|
+
|
|
136
|
+
### `migrations/` stops being mostly empty
|
|
137
|
+
|
|
138
|
+
After `users-web`, the app gets real schema files such as:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
migrations/
|
|
142
|
+
2026..._users-core-generic-initial-schema.cjs
|
|
143
|
+
2026..._users-core-profile-username-schema.cjs
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
These files are the first real database schema in the guide.
|
|
147
|
+
|
|
148
|
+
The important initial migration creates:
|
|
149
|
+
|
|
150
|
+
- `users`
|
|
151
|
+
- `user_settings`
|
|
152
|
+
|
|
153
|
+
That is why this chapter needs `npm run db:migrate` in a much more serious way than the previous one did.
|
|
154
|
+
|
|
155
|
+
### `config/public.js` gains one new authenticated surface
|
|
156
|
+
|
|
157
|
+
After the install, `config/public.js` grows one important surface definition:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
config.surfaceDefinitions.account = {
|
|
161
|
+
id: "account",
|
|
162
|
+
label: "Account",
|
|
163
|
+
pagesRoot: "account",
|
|
164
|
+
enabled: true,
|
|
165
|
+
requiresAuth: true,
|
|
166
|
+
requiresWorkspace: false,
|
|
167
|
+
origin: ""
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This chapter keeps the split simple:
|
|
172
|
+
|
|
173
|
+
- `account` is the normal authenticated user area
|
|
174
|
+
- operator surfaces such as `console` are introduced later, by packages that actually own them
|
|
175
|
+
|
|
176
|
+
### `src/placement.js` grows account entries
|
|
177
|
+
|
|
178
|
+
The placement registry also becomes more interesting:
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
addPlacement({
|
|
182
|
+
id: "users.profile.menu.settings",
|
|
183
|
+
target: "auth-profile-menu:primary-menu",
|
|
184
|
+
surfaces: ["*"],
|
|
185
|
+
order: 500,
|
|
186
|
+
componentToken: "auth.web.profile.menu.link-item",
|
|
187
|
+
props: {
|
|
188
|
+
label: "Settings",
|
|
189
|
+
to: "/account"
|
|
190
|
+
},
|
|
191
|
+
when: ({ auth }) => Boolean(auth?.authenticated)
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
This chapter is the first one where one package install adds meaningful authenticated shell entries and a real account surface.
|
|
196
|
+
|
|
197
|
+
### `src/pages/account/index.vue` is a real authenticated route
|
|
198
|
+
|
|
199
|
+
The account route itself is very small:
|
|
200
|
+
|
|
201
|
+
```vue
|
|
202
|
+
<route lang="json">
|
|
203
|
+
{
|
|
204
|
+
"meta": {
|
|
205
|
+
"guard": {
|
|
206
|
+
"policy": "authenticated"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
</route>
|
|
211
|
+
|
|
212
|
+
<template>
|
|
213
|
+
<AccountSettingsClientElement />
|
|
214
|
+
</template>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
That is a very JSKIT-style file.
|
|
218
|
+
|
|
219
|
+
- the route policy is app-owned
|
|
220
|
+
- the page wrapper is app-owned
|
|
221
|
+
- the heavy UI is delegated to a reusable client element
|
|
222
|
+
|
|
223
|
+
So the route is simple, but it is already a real authenticated account screen rather than a placeholder card.
|
|
224
|
+
|
|
225
|
+
### The account screen itself is scaffolded app-owned UI
|
|
226
|
+
|
|
227
|
+
The account page is backed by:
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
src/components/account/settings/
|
|
231
|
+
AccountSettingsClientElement.vue
|
|
232
|
+
AccountSettingsProfileSection.vue
|
|
233
|
+
AccountSettingsPreferencesSection.vue
|
|
234
|
+
AccountSettingsNotificationsSection.vue
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The top-level `AccountSettingsClientElement.vue` uses `useAccountSettingsRuntime()` from `users-web` and wires those sections into a tabbed settings experience.
|
|
238
|
+
|
|
239
|
+
That is worth noticing because the guide has now reached a new level of scaffolding:
|
|
240
|
+
|
|
241
|
+
- earlier chapters mostly introduced shells and routes
|
|
242
|
+
- this chapter introduces real app-owned feature UI that is already split into reusable sections
|
|
243
|
+
|
|
244
|
+
## Under the hood
|
|
245
|
+
|
|
246
|
+
### Why auth now behaves differently
|
|
247
|
+
|
|
248
|
+
In the previous chapter, auth still defaulted to the standalone profile sync fallback. The core logic in `AuthSupabaseServiceProvider` looks like this:
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
const authProfileMode = resolveAuthProfileMode(env);
|
|
252
|
+
let userProfileSyncService = fallbackStandaloneProfileSyncService;
|
|
253
|
+
|
|
254
|
+
if (authProfileMode === AUTH_PROFILE_MODE_USERS) {
|
|
255
|
+
if (!scope.has("users.profile.sync.service")) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"AuthSupabaseServiceProvider requires users.profile.sync.service when AUTH_PROFILE_MODE=users."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
userProfileSyncService = scope.make("users.profile.sync.service");
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The important part is no longer hypothetical.
|
|
265
|
+
|
|
266
|
+
After `users-web`:
|
|
267
|
+
|
|
268
|
+
- `.env` sets `AUTH_PROFILE_MODE=users`
|
|
269
|
+
- `users-core` supplies the users-backed sync service
|
|
270
|
+
- the migrations supply the required tables
|
|
271
|
+
|
|
272
|
+
So auth now has everything it needs to stop using the fallback mirror and start using the persistent users-backed one.
|
|
273
|
+
|
|
274
|
+
That is the true point of this chapter. The app is no longer just authenticated. It now has a real users layer.
|
|
275
|
+
|
|
276
|
+
### `users-core` also owns the profile-sync lifecycle registry
|
|
277
|
+
|
|
278
|
+
There is one more seam worth noticing here because later packages depend on it.
|
|
279
|
+
|
|
280
|
+
The important thing to understand is that the public extension API is:
|
|
281
|
+
|
|
282
|
+
```js
|
|
283
|
+
registerProfileSyncLifecycleContributor(...)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
That is the function another server package uses when it wants to run logic after JSKIT has created or synchronized a user record.
|
|
287
|
+
|
|
288
|
+
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:
|
|
289
|
+
|
|
290
|
+
```js
|
|
291
|
+
import { registerProfileSyncLifecycleContributor } from "@jskit-ai/users-core/server/profileSyncLifecycleContributorRegistry";
|
|
292
|
+
|
|
293
|
+
function registerExampleCore(app) {
|
|
294
|
+
registerProfileSyncLifecycleContributor(app, "example.core.profileSyncLogger", () => {
|
|
295
|
+
return {
|
|
296
|
+
contributorId: "example.core.profileSyncLogger",
|
|
297
|
+
order: 0,
|
|
298
|
+
async afterIdentityProfileSynced({ profile, created } = {}) {
|
|
299
|
+
if (!profile) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (created) {
|
|
304
|
+
console.log("Created JSKIT user:", profile.id, profile.email);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log("Synchronized existing JSKIT user:", profile.id, profile.email);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
That example is deliberately simple, but it shows the real usage pattern:
|
|
316
|
+
|
|
317
|
+
- import `registerProfileSyncLifecycleContributor(...)`
|
|
318
|
+
- call it from your package's server registration code
|
|
319
|
+
- implement `afterIdentityProfileSynced(...)`
|
|
320
|
+
- use `created` to tell "brand-new user" apart from "existing user synchronized again"
|
|
321
|
+
|
|
322
|
+
In a real package, the same seam is useful for things like:
|
|
323
|
+
|
|
324
|
+
- provisioning related rows when a user is created
|
|
325
|
+
- seeding package-owned settings
|
|
326
|
+
- writing audit events
|
|
327
|
+
- attaching app-owned resources to the new user
|
|
328
|
+
|
|
329
|
+
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.
|
|
330
|
+
|
|
331
|
+
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.
|
|
332
|
+
|
|
333
|
+
- `users-core` owns the tagged registry and the execution point
|
|
334
|
+
- auth still only calls one service: `users.profile.sync.service`
|
|
335
|
+
- other packages extend the post-sync lifecycle by registering contributors
|
|
336
|
+
|
|
337
|
+
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.
|
|
338
|
+
|
|
339
|
+
## Summary
|
|
340
|
+
|
|
341
|
+
This chapter is where the app stopped treating signed-in people as only Supabase identities and started treating them as real JSKIT users.
|
|
342
|
+
|
|
343
|
+
- `users-core` installed the persistent users/account schema and server layer
|
|
344
|
+
- `users-web` installed the first real account surface and account settings UI
|
|
345
|
+
- auth switched from the standalone fallback mirror to the users-backed sync flow
|
|
346
|
+
|
|
347
|
+
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."
|
|
348
|
+
|
|
349
|
+
At the end of this chapter, the app now has:
|
|
350
|
+
|
|
351
|
+
- real JSKIT-side `users` and `user_settings` tables
|
|
352
|
+
- a real authenticated `/account` surface
|
|
353
|
+
- a shell that can expose user settings and account tools
|
|
354
|
+
|
|
355
|
+
The next chapter adds a different kind of surface: not a personal account area, but a privileged operator console.
|