@jskit-ai/agent-docs 0.1.149 → 0.1.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/guide/agent/app-setup/existing-application-migration.md +8 -6
- package/guide/agent/app-setup/initial-scaffolding.md +9 -7
- package/guide/agent/app-setup/quickstart.md +9 -6
- package/guide/agent/framework/application-operations.md +91 -0
- package/guide/agent/framework/crud-operations.md +83 -0
- package/guide/agent/framework/material-3.md +112 -0
- package/guide/agent/framework/ui-operations.md +78 -0
- package/guide/agent/index.md +13 -3
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/example/AGENTS.md +8 -8
- package/patterns/minimal-foundation/example/package.json +4 -5
- package/patterns/shell-foundation/example/AGENTS.md +8 -8
- package/patterns/shell-foundation/example/package.json +5 -6
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/reference/autogen/PATTERN_INDEX.md +61 -61
- package/skills/jskit/SKILL.md +8 -5
- package/skills/jskit/references/app-operations.md +12 -11
- package/skills/jskit/references/crud-operations.md +10 -6
- package/skills/jskit/references/existing-application-migration.md +9 -12
- package/skills/jskit/references/material-3.md +2 -0
- package/skills/jskit/references/pattern-index.md +61 -61
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +105 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/.nvmrc +1 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +17 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/Procfile +2 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/app.json +14 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +71 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/server.js +8 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/public.js +40 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/server.js +1 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +19 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/favicon.svg +7 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/gitignore +9 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/index.html +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/jsconfig.json +8 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +62 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/package.json +42 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +31 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +195 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/App.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/main.js +85 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home/index.vue +48 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/views/NotFound.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +16 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/vite.config.mjs +80 -0
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +111 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/.nvmrc +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +17 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/Procfile +2 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/app.json +14 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +71 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/server.js +8 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/public.js +40 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/server.js +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/favicon.svg +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/gitignore +9 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/index.html +13 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/jsconfig.json +8 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +64 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +56 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/index.js +9 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/index.js +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +31 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +195 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/App.vue +11 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/ShellLayout.vue +12 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/error.js +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/main.js +85 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/index.vue +116 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings.vue +109 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home.vue +20 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/placement.js +56 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/placementTopology.js +149 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/views/NotFound.vue +13 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +16 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/vite.config.mjs +80 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md +77 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/public.js +19 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/server.js +9 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/assistant/index.vue +7 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/settings/assistant/index.vue +7 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/placement.js +38 -0
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +90 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/login.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/reset-password.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/signout.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authGuardRuntime.js +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authHttpClient.js +1 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/useSignOut.js +1 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/LoginView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/ResetPasswordView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/SignOutView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +5 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/PATTERN.md +67 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/.env.example +4 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/config/server.js +11 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +7 -0
- package/skills/jskit/references/patterns/console/console-surface/PATTERN.md +58 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/index.vue +62 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings/index.vue +17 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings.vue +95 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console.vue +20 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +88 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +54 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookFormFields.vue +52 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue +54 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +45 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookViewPage.vue +50 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/formFields.js +31 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/listExtensions.js +9 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +160 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/migrations/20260815000000_books.cjs +22 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +41 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/BooksFeature.js +13 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/bookResource.js +83 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +102 -0
- package/skills/jskit/references/patterns/crud/resource-contract/example/bookResource.js +87 -0
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +80 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/.env.example +5 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/.github/workflows/verify.yml +39 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +11 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +13 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +3 -0
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +80 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/.env.example +5 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/.github/workflows/verify.yml +38 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +11 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +13 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +3 -0
- package/skills/jskit/references/patterns/mobile/android-application/PATTERN.md +71 -0
- package/skills/jskit/references/patterns/mobile/android-application/example/capacitor.config.json +10 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md +69 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/.env.example +1 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +8 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/src/placement.js +17 -0
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +108 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +48 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +34 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +23 -0
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +66 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/App.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home/index.vue +48 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/App.vue +11 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/ShellLayout.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/MenuLinkItem.vue +30 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/TabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/error.js +19 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/index.vue +106 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/general/index.vue +40 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/index.vue +7 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings.vue +109 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home.vue +20 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/placement.js +56 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/placementTopology.js +149 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/tests/e2e/adaptive-shell.spec.ts +10 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md +76 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/packages/main/src/client/providers/MainClientProvider.js +14 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/components/SyncStatusElement.vue +16 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/activity.vue +8 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/index.vue +7 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/overview.vue +8 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue +33 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placement.js +52 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +29 -0
- package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +61 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue +81 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +151 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +120 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/index.vue +17 -0
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +64 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +42 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/UsersFeature.js +13 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userResource.js +69 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +43 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +22 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userResource.js +56 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +60 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/config/roles.js +27 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +23 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md +63 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue +106 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountSettingsInvitesSection.vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/components/WorkspaceNotFoundCard.vue +53 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/composables/useWorkspaceNotFoundState.js +41 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/members/index.vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings/index.vue +23 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings.vue +95 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/invite/[token].vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/index.vue +85 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/root.vue +20 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/index.vue +46 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/root.vue +20 -0
- package/skills/jskit/references/ui-operations.md +5 -3
- package/templates/app/AGENTS.md +8 -8
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createPlacementRegistry } from "@jskit-ai/shell-web/client/placement";
|
|
2
|
+
|
|
3
|
+
const registry = createPlacementRegistry();
|
|
4
|
+
const { addPlacement } = registry;
|
|
5
|
+
|
|
6
|
+
addPlacement({
|
|
7
|
+
id: "catalogue.reports.link",
|
|
8
|
+
target: "shell.primary-nav",
|
|
9
|
+
kind: "link",
|
|
10
|
+
surfaces: ["home"],
|
|
11
|
+
order: 120,
|
|
12
|
+
props: {
|
|
13
|
+
label: "Reports",
|
|
14
|
+
icon: "mdi-chart-box-outline",
|
|
15
|
+
surface: "home",
|
|
16
|
+
scopedSuffix: "/reports",
|
|
17
|
+
unscopedSuffix: "/reports"
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
for (const [id, label, suffix, order] of [
|
|
22
|
+
["overview", "Overview", "/reports/overview", 100],
|
|
23
|
+
["activity", "Activity", "/reports/activity", 110]
|
|
24
|
+
]) {
|
|
25
|
+
addPlacement({
|
|
26
|
+
id: `catalogue.reports.${id}.link`,
|
|
27
|
+
target: "page.section-nav",
|
|
28
|
+
owner: "reports",
|
|
29
|
+
kind: "link",
|
|
30
|
+
surfaces: ["home"],
|
|
31
|
+
order,
|
|
32
|
+
props: {
|
|
33
|
+
label,
|
|
34
|
+
surface: "home",
|
|
35
|
+
scopedSuffix: suffix,
|
|
36
|
+
unscopedSuffix: suffix
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
addPlacement({
|
|
42
|
+
id: "catalogue.sync-status",
|
|
43
|
+
target: "shell.status",
|
|
44
|
+
kind: "component",
|
|
45
|
+
surfaces: ["home"],
|
|
46
|
+
order: 100,
|
|
47
|
+
componentToken: "local.main.ui.sync-status"
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export default function getPlacements() {
|
|
51
|
+
return registry.build();
|
|
52
|
+
}
|
package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const placements = [];
|
|
2
|
+
|
|
3
|
+
function addPlacementTopology(value = {}) {
|
|
4
|
+
placements.push(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
addPlacementTopology({
|
|
8
|
+
id: "page.section-nav",
|
|
9
|
+
owner: "reports",
|
|
10
|
+
description: "Navigation between report pages.",
|
|
11
|
+
surfaces: ["home"],
|
|
12
|
+
variants: {
|
|
13
|
+
compact: {
|
|
14
|
+
outlet: "reports:section-nav",
|
|
15
|
+
renderers: { link: "local.main.ui.tab-link-item" }
|
|
16
|
+
},
|
|
17
|
+
medium: {
|
|
18
|
+
outlet: "reports:section-nav",
|
|
19
|
+
renderers: { link: "local.main.ui.tab-link-item" }
|
|
20
|
+
},
|
|
21
|
+
expanded: {
|
|
22
|
+
outlet: "reports:section-nav",
|
|
23
|
+
renderers: { link: "local.main.ui.tab-link-item" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export { addPlacementTopology };
|
|
29
|
+
export default { placements };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: users/account-settings
|
|
3
|
+
title: Account settings surface
|
|
4
|
+
summary: Compose an account settings route and profile, preference, and notification sections from JSKIT user web components.
|
|
5
|
+
keywords: account, notifications, preferences, profile, settings, user, vue
|
|
6
|
+
requires: @jskit-ai/users-core, @jskit-ai/users-web, @jskit-ai/shell-web
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Account settings surface
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when authenticated users need to manage their own profile and
|
|
14
|
+
account preferences.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
Do not use this pattern for administrator-managed users, authentication
|
|
19
|
+
credential storage, or anonymous profile editing.
|
|
20
|
+
|
|
21
|
+
## Product decisions
|
|
22
|
+
|
|
23
|
+
Choose editable profile fields, preference vocabulary, notification options,
|
|
24
|
+
section order, and which account operations require reauthentication.
|
|
25
|
+
|
|
26
|
+
## Framework APIs
|
|
27
|
+
|
|
28
|
+
Use account settings elements and composables from `@jskit-ai/users-web`,
|
|
29
|
+
ordinary `useCommand()` mutation behavior, and JSKIT shell placements.
|
|
30
|
+
|
|
31
|
+
## Invariants
|
|
32
|
+
|
|
33
|
+
- Sections use JSKIT account settings APIs rather than direct HTTP helpers.
|
|
34
|
+
- Cached resource data hydrates local writable fields immediately.
|
|
35
|
+
- Mutation errors use the standard toast and do not push the form down.
|
|
36
|
+
- Loading uses layout-stable skeletons, never an indeterminate spinner.
|
|
37
|
+
- Pending controls keep stable labels and prevent duplicate submission.
|
|
38
|
+
- The route and placement owner agree.
|
|
39
|
+
|
|
40
|
+
## Example files
|
|
41
|
+
|
|
42
|
+
`example/` contains an account route and three concrete settings sections.
|
|
43
|
+
Adapt their fields and copy while retaining the shared account runtime.
|
|
44
|
+
|
|
45
|
+
## Variation points
|
|
46
|
+
|
|
47
|
+
Change sections, fields, copy, order, permissions, preference choices, and
|
|
48
|
+
notification vocabulary while keeping server-owned validation authoritative.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
Navigate away and back with warm cache, exercise browser back/forward, save and
|
|
53
|
+
clear fields, verify toast errors, inspect skeleton geometry, and test keyboard
|
|
54
|
+
operation at compact and expanded widths.
|
|
55
|
+
|
|
56
|
+
## Avoid
|
|
57
|
+
|
|
58
|
+
- page-local request clients
|
|
59
|
+
- inline mutation alerts that shift content
|
|
60
|
+
- lazy non-immediate watchers for initial hydration
|
|
61
|
+
- copied user repositories or generator source markers
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
runtime: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const notifications = props.runtime.notifications;
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<v-sheet rounded="lg" border class="account-settings-section">
|
|
14
|
+
<header class="account-settings-section__header">
|
|
15
|
+
<h2 class="account-settings-section__title">Notifications</h2>
|
|
16
|
+
</header>
|
|
17
|
+
<div class="account-settings-section__body">
|
|
18
|
+
<v-form @submit.prevent="notifications.submit" novalidate>
|
|
19
|
+
<v-switch
|
|
20
|
+
v-model="notifications.form.productUpdates"
|
|
21
|
+
label="Product updates"
|
|
22
|
+
color="primary"
|
|
23
|
+
hide-details
|
|
24
|
+
:disabled="notifications.isSaving.value || notifications.isRefreshing.value"
|
|
25
|
+
class="mb-2"
|
|
26
|
+
/>
|
|
27
|
+
<v-switch
|
|
28
|
+
v-model="notifications.form.accountActivity"
|
|
29
|
+
label="Account activity alerts"
|
|
30
|
+
color="primary"
|
|
31
|
+
hide-details
|
|
32
|
+
:disabled="notifications.isSaving.value || notifications.isRefreshing.value"
|
|
33
|
+
class="mb-2"
|
|
34
|
+
/>
|
|
35
|
+
<v-switch
|
|
36
|
+
v-model="notifications.form.securityAlerts"
|
|
37
|
+
label="Security alerts (required)"
|
|
38
|
+
color="primary"
|
|
39
|
+
hide-details
|
|
40
|
+
disabled
|
|
41
|
+
class="mb-4"
|
|
42
|
+
/>
|
|
43
|
+
<v-btn
|
|
44
|
+
type="submit"
|
|
45
|
+
color="primary"
|
|
46
|
+
:loading="notifications.isSaving.value"
|
|
47
|
+
:disabled="notifications.isRefreshing.value"
|
|
48
|
+
>
|
|
49
|
+
Save notification settings
|
|
50
|
+
</v-btn>
|
|
51
|
+
</v-form>
|
|
52
|
+
</div>
|
|
53
|
+
</v-sheet>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.account-settings-section {
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.account-settings-section__header {
|
|
62
|
+
padding: 1rem 1rem 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.account-settings-section__title {
|
|
66
|
+
font-size: 1rem;
|
|
67
|
+
font-weight: 650;
|
|
68
|
+
line-height: 1.2;
|
|
69
|
+
margin: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.account-settings-section__body {
|
|
73
|
+
padding: 1rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (max-width: 640px) {
|
|
77
|
+
.account-settings-section__body :deep(.v-btn) {
|
|
78
|
+
min-height: 48px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
runtime: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const preferences = props.runtime.preferences;
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<v-sheet rounded="lg" border class="account-settings-section">
|
|
14
|
+
<header class="account-settings-section__header">
|
|
15
|
+
<h2 class="account-settings-section__title">Preferences</h2>
|
|
16
|
+
</header>
|
|
17
|
+
<div class="account-settings-section__body">
|
|
18
|
+
<v-form @submit.prevent="preferences.submit" novalidate>
|
|
19
|
+
<v-row>
|
|
20
|
+
<v-col cols="12" md="4">
|
|
21
|
+
<v-select
|
|
22
|
+
v-model="preferences.form.theme"
|
|
23
|
+
label="Theme"
|
|
24
|
+
:items="preferences.options.theme"
|
|
25
|
+
item-title="title"
|
|
26
|
+
item-value="value"
|
|
27
|
+
variant="outlined"
|
|
28
|
+
density="comfortable"
|
|
29
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
30
|
+
:error-messages="preferences.fieldErrors.theme ? [preferences.fieldErrors.theme] : []"
|
|
31
|
+
/>
|
|
32
|
+
</v-col>
|
|
33
|
+
|
|
34
|
+
<v-col cols="12" md="4">
|
|
35
|
+
<v-select
|
|
36
|
+
v-model="preferences.form.locale"
|
|
37
|
+
label="Language / locale"
|
|
38
|
+
:items="preferences.options.locale"
|
|
39
|
+
item-title="title"
|
|
40
|
+
item-value="value"
|
|
41
|
+
variant="outlined"
|
|
42
|
+
density="comfortable"
|
|
43
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
44
|
+
:error-messages="preferences.fieldErrors.locale ? [preferences.fieldErrors.locale] : []"
|
|
45
|
+
/>
|
|
46
|
+
</v-col>
|
|
47
|
+
|
|
48
|
+
<v-col cols="12" md="4">
|
|
49
|
+
<v-select
|
|
50
|
+
v-model="preferences.form.timeZone"
|
|
51
|
+
label="Time zone"
|
|
52
|
+
:items="preferences.options.timeZone"
|
|
53
|
+
variant="outlined"
|
|
54
|
+
density="comfortable"
|
|
55
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
56
|
+
:error-messages="preferences.fieldErrors.timeZone ? [preferences.fieldErrors.timeZone] : []"
|
|
57
|
+
/>
|
|
58
|
+
</v-col>
|
|
59
|
+
|
|
60
|
+
<v-col cols="12" md="4">
|
|
61
|
+
<v-select
|
|
62
|
+
v-model="preferences.form.dateFormat"
|
|
63
|
+
label="Date format"
|
|
64
|
+
:items="preferences.options.dateFormat"
|
|
65
|
+
item-title="title"
|
|
66
|
+
item-value="value"
|
|
67
|
+
variant="outlined"
|
|
68
|
+
density="comfortable"
|
|
69
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
70
|
+
:error-messages="preferences.fieldErrors.dateFormat ? [preferences.fieldErrors.dateFormat] : []"
|
|
71
|
+
/>
|
|
72
|
+
</v-col>
|
|
73
|
+
|
|
74
|
+
<v-col cols="12" md="4">
|
|
75
|
+
<v-select
|
|
76
|
+
v-model="preferences.form.numberFormat"
|
|
77
|
+
label="Number format"
|
|
78
|
+
:items="preferences.options.numberFormat"
|
|
79
|
+
item-title="title"
|
|
80
|
+
item-value="value"
|
|
81
|
+
variant="outlined"
|
|
82
|
+
density="comfortable"
|
|
83
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
84
|
+
:error-messages="preferences.fieldErrors.numberFormat ? [preferences.fieldErrors.numberFormat] : []"
|
|
85
|
+
/>
|
|
86
|
+
</v-col>
|
|
87
|
+
|
|
88
|
+
<v-col cols="12" md="4">
|
|
89
|
+
<v-select
|
|
90
|
+
v-model="preferences.form.currencyCode"
|
|
91
|
+
label="Currency"
|
|
92
|
+
:items="preferences.options.currency"
|
|
93
|
+
variant="outlined"
|
|
94
|
+
density="comfortable"
|
|
95
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
96
|
+
:error-messages="preferences.fieldErrors.currencyCode ? [preferences.fieldErrors.currencyCode] : []"
|
|
97
|
+
/>
|
|
98
|
+
</v-col>
|
|
99
|
+
|
|
100
|
+
<v-col cols="12" md="3">
|
|
101
|
+
<v-select
|
|
102
|
+
v-model.number="preferences.form.avatarSize"
|
|
103
|
+
label="Avatar size"
|
|
104
|
+
:items="preferences.options.avatarSize"
|
|
105
|
+
variant="outlined"
|
|
106
|
+
density="comfortable"
|
|
107
|
+
:disabled="preferences.isSaving.value || preferences.isRefreshing.value"
|
|
108
|
+
:error-messages="preferences.fieldErrors.avatarSize ? [preferences.fieldErrors.avatarSize] : []"
|
|
109
|
+
/>
|
|
110
|
+
</v-col>
|
|
111
|
+
</v-row>
|
|
112
|
+
|
|
113
|
+
<v-btn
|
|
114
|
+
type="submit"
|
|
115
|
+
color="primary"
|
|
116
|
+
:loading="preferences.isSaving.value"
|
|
117
|
+
:disabled="preferences.isRefreshing.value"
|
|
118
|
+
>
|
|
119
|
+
Save preferences
|
|
120
|
+
</v-btn>
|
|
121
|
+
</v-form>
|
|
122
|
+
</div>
|
|
123
|
+
</v-sheet>
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<style scoped>
|
|
127
|
+
.account-settings-section {
|
|
128
|
+
overflow: hidden;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.account-settings-section__header {
|
|
132
|
+
padding: 1rem 1rem 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.account-settings-section__title {
|
|
136
|
+
font-size: 1rem;
|
|
137
|
+
font-weight: 650;
|
|
138
|
+
line-height: 1.2;
|
|
139
|
+
margin: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.account-settings-section__body {
|
|
143
|
+
padding: 1rem;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@media (max-width: 640px) {
|
|
147
|
+
.account-settings-section__body :deep(.v-btn) {
|
|
148
|
+
min-height: 48px;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
runtime: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const profile = props.runtime.profile;
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<v-sheet rounded="lg" border class="account-settings-section">
|
|
14
|
+
<header class="account-settings-section__header">
|
|
15
|
+
<h2 class="account-settings-section__title">Profile</h2>
|
|
16
|
+
</header>
|
|
17
|
+
<div class="account-settings-section__body">
|
|
18
|
+
<v-form @submit.prevent="profile.submit" novalidate>
|
|
19
|
+
<v-row class="mb-2">
|
|
20
|
+
<v-col cols="12" md="4" class="d-flex flex-column align-center justify-center">
|
|
21
|
+
<v-avatar :size="profile.avatar.size" color="surface-variant" rounded="circle" class="mb-3">
|
|
22
|
+
<v-img v-if="profile.avatar.effectiveUrl" :src="profile.avatar.effectiveUrl" cover />
|
|
23
|
+
<span v-else class="text-h6">{{ profile.initials.value }}</span>
|
|
24
|
+
</v-avatar>
|
|
25
|
+
<div class="text-caption text-medium-emphasis">Preview size: {{ profile.avatar.size }} px</div>
|
|
26
|
+
</v-col>
|
|
27
|
+
|
|
28
|
+
<v-col cols="12" md="8">
|
|
29
|
+
<div class="d-flex flex-wrap ga-2 mb-2">
|
|
30
|
+
<v-btn
|
|
31
|
+
variant="tonal"
|
|
32
|
+
color="secondary"
|
|
33
|
+
:disabled="profile.isSaving.value || profile.isDeletingAvatar.value || profile.isRefreshing.value"
|
|
34
|
+
@click="profile.openAvatarEditor"
|
|
35
|
+
>
|
|
36
|
+
Replace avatar
|
|
37
|
+
</v-btn>
|
|
38
|
+
<v-btn
|
|
39
|
+
v-if="profile.avatar.hasUploadedAvatar"
|
|
40
|
+
variant="text"
|
|
41
|
+
color="error"
|
|
42
|
+
:loading="profile.isDeletingAvatar.value"
|
|
43
|
+
:disabled="profile.isSaving.value || profile.isRefreshing.value"
|
|
44
|
+
@click="profile.removeAvatar"
|
|
45
|
+
>
|
|
46
|
+
Remove avatar
|
|
47
|
+
</v-btn>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div v-if="profile.selectedAvatarFileName.value" class="text-caption text-medium-emphasis mb-2">
|
|
51
|
+
Selected file: {{ profile.selectedAvatarFileName.value }}
|
|
52
|
+
</div>
|
|
53
|
+
</v-col>
|
|
54
|
+
</v-row>
|
|
55
|
+
|
|
56
|
+
<v-row>
|
|
57
|
+
<v-col cols="12" md="6">
|
|
58
|
+
<v-text-field
|
|
59
|
+
v-model="profile.form.displayName"
|
|
60
|
+
label="Display name"
|
|
61
|
+
variant="outlined"
|
|
62
|
+
density="comfortable"
|
|
63
|
+
autocomplete="nickname"
|
|
64
|
+
:readonly="profile.isSaving.value || profile.isRefreshing.value"
|
|
65
|
+
:error-messages="profile.fieldErrors.displayName ? [profile.fieldErrors.displayName] : []"
|
|
66
|
+
/>
|
|
67
|
+
</v-col>
|
|
68
|
+
|
|
69
|
+
<v-col cols="12" md="6">
|
|
70
|
+
<v-text-field
|
|
71
|
+
v-model="profile.form.email"
|
|
72
|
+
label="Email"
|
|
73
|
+
variant="outlined"
|
|
74
|
+
density="comfortable"
|
|
75
|
+
readonly
|
|
76
|
+
hint="Managed by your sign-in account"
|
|
77
|
+
persistent-hint
|
|
78
|
+
/>
|
|
79
|
+
</v-col>
|
|
80
|
+
</v-row>
|
|
81
|
+
|
|
82
|
+
<v-btn
|
|
83
|
+
type="submit"
|
|
84
|
+
color="primary"
|
|
85
|
+
:loading="profile.isSaving.value"
|
|
86
|
+
:disabled="profile.isDeletingAvatar.value || profile.isRefreshing.value"
|
|
87
|
+
>
|
|
88
|
+
Save profile
|
|
89
|
+
</v-btn>
|
|
90
|
+
</v-form>
|
|
91
|
+
</div>
|
|
92
|
+
</v-sheet>
|
|
93
|
+
</template>
|
|
94
|
+
|
|
95
|
+
<style scoped>
|
|
96
|
+
.account-settings-section {
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.account-settings-section__header {
|
|
101
|
+
padding: 1rem 1rem 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.account-settings-section__title {
|
|
105
|
+
font-size: 1rem;
|
|
106
|
+
font-weight: 650;
|
|
107
|
+
line-height: 1.2;
|
|
108
|
+
margin: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.account-settings-section__body {
|
|
112
|
+
padding: 1rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@media (max-width: 640px) {
|
|
116
|
+
.account-settings-section__body :deep(.v-btn) {
|
|
117
|
+
min-height: 48px;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
</style>
|
package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/index.vue
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<route lang="json">
|
|
2
|
+
{
|
|
3
|
+
"meta": {
|
|
4
|
+
"guard": {
|
|
5
|
+
"policy": "authenticated"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
</route>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<AccountSettingsClientElement />
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import AccountSettingsClientElement from "@jskit-ai/users-web/client/components/AccountSettingsClientElement";
|
|
17
|
+
</script>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: users/user-administration-server
|
|
3
|
+
title: User administration server package
|
|
4
|
+
summary: Expose user administration and workspace-scoped member operations through app-owned packages backed by JSKIT users runtime APIs.
|
|
5
|
+
keywords: account, admin, member, repository, resource, routes, service, user, workspace
|
|
6
|
+
requires: @jskit-ai/users-core, @jskit-ai/crud-core
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# User administration server package
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when an application needs app-specific administration of user
|
|
14
|
+
profiles or workspace members beyond the built-in account runtime.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
Do not use this pattern for self-service account settings, authentication
|
|
19
|
+
credentials, or an application that needs no administrative user listing.
|
|
20
|
+
|
|
21
|
+
## Product decisions
|
|
22
|
+
|
|
23
|
+
Choose global versus workspace scope, visible and editable fields, permission
|
|
24
|
+
policy, route surface, filters, and whether account deletion is part of the
|
|
25
|
+
product. Do not expose password/session data through the resource.
|
|
26
|
+
|
|
27
|
+
## Framework APIs
|
|
28
|
+
|
|
29
|
+
Use `@jskit-ai/users-core` for profile persistence and policies,
|
|
30
|
+
`defineCrudJsonApiFeature()` from `@jskit-ai/crud-core` for standard mechanics,
|
|
31
|
+
and the resource contracts from `@jskit-ai/resource-crud-core`.
|
|
32
|
+
|
|
33
|
+
## Invariants
|
|
34
|
+
|
|
35
|
+
- The public user id is the resource identity.
|
|
36
|
+
- Workspace operations are scoped before repository access.
|
|
37
|
+
- Permission checks happen before records or record existence are disclosed.
|
|
38
|
+
- Shared profile persistence remains owned by `@jskit-ai/users-core`.
|
|
39
|
+
- The resource is the field contract; the feature projects its repository,
|
|
40
|
+
service, actions, and routes without app-local ceremony.
|
|
41
|
+
|
|
42
|
+
## Example files
|
|
43
|
+
|
|
44
|
+
`example/packages/users/` is a global administration package.
|
|
45
|
+
`example/packages/users-workspace/` demonstrates the workspace route/action
|
|
46
|
+
boundary while reusing the same service contract. Copy only the composition
|
|
47
|
+
that matches the product and adapt it as ordinary application source.
|
|
48
|
+
|
|
49
|
+
## Variation points
|
|
50
|
+
|
|
51
|
+
Change scope, route surface, visible fields, filters, sorting, permission
|
|
52
|
+
policy, and user-facing language. Retain the core user identity contract.
|
|
53
|
+
|
|
54
|
+
## Verification
|
|
55
|
+
|
|
56
|
+
Test authorized and forbidden list/view/update operations, cross-workspace
|
|
57
|
+
isolation, missing records, null/cleared fields, filtering, and pagination.
|
|
58
|
+
|
|
59
|
+
## Avoid
|
|
60
|
+
|
|
61
|
+
- copying authentication credential tables into the user resource
|
|
62
|
+
- trusting route scope without repository scope
|
|
63
|
+
- adding app-local mechanics already provided by `defineCrudJsonApiFeature()`
|
|
64
|
+
- generator metadata or field questionnaires
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/users",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "App-local read-only user administration feature.",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./server/UsersFeature": "./src/server/UsersFeature.js",
|
|
9
|
+
"./shared": "./src/shared/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@jskit-ai/crud-core": "0.1.189",
|
|
13
|
+
"@jskit-ai/resource-crud-core": "0.1.120"
|
|
14
|
+
},
|
|
15
|
+
"jskit": {
|
|
16
|
+
"kind": "runtime",
|
|
17
|
+
"capabilities": {
|
|
18
|
+
"provides": [
|
|
19
|
+
"app.users"
|
|
20
|
+
],
|
|
21
|
+
"requires": [
|
|
22
|
+
"runtime.http",
|
|
23
|
+
"runtime.json-rest-api",
|
|
24
|
+
"runtime.actions",
|
|
25
|
+
"runtime.database"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"runtime": {
|
|
29
|
+
"server": {
|
|
30
|
+
"providers": [
|
|
31
|
+
{
|
|
32
|
+
"entrypoint": "src/server/UsersFeature.js",
|
|
33
|
+
"export": "UsersFeature"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"client": {
|
|
38
|
+
"providers": []
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineCrudJsonApiFeature } from "@jskit-ai/crud-core/server/defineCrudJsonApiFeature";
|
|
2
|
+
import { resource } from "../shared/userResource.js";
|
|
3
|
+
|
|
4
|
+
const UsersFeature = defineCrudJsonApiFeature({
|
|
5
|
+
resource,
|
|
6
|
+
id: "app.users",
|
|
7
|
+
capability: "app.users",
|
|
8
|
+
surface: "home",
|
|
9
|
+
ownershipFilter: "public",
|
|
10
|
+
relativePath: "/users"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export { UsersFeature };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { resource } from "./userResource.js";
|