create-questpie 2.0.4 → 2.1.0

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 (152) hide show
  1. package/dist/index.mjs +362 -119
  2. package/package.json +2 -3
  3. package/templates/elysia/AGENTS.md +56 -0
  4. package/templates/elysia/CLAUDE.md +39 -0
  5. package/templates/elysia/Dockerfile +24 -0
  6. package/templates/elysia/README.md +148 -0
  7. package/templates/elysia/docker/init-extensions.sql +11 -0
  8. package/templates/elysia/docker-compose.yml +21 -0
  9. package/templates/elysia/env.example +16 -0
  10. package/templates/elysia/gitignore +6 -0
  11. package/templates/elysia/package.json +47 -0
  12. package/templates/elysia/questpie.config.ts +12 -0
  13. package/templates/elysia/src/index.ts +21 -0
  14. package/templates/elysia/src/lib/auth-client.ts +32 -0
  15. package/templates/elysia/src/lib/client.ts +13 -0
  16. package/templates/elysia/src/lib/env.ts +24 -0
  17. package/templates/elysia/src/lib/query-client.ts +18 -0
  18. package/templates/elysia/src/lib/query.ts +18 -0
  19. package/templates/elysia/src/questpie/server/.generated/context.gen.ts +200 -0
  20. package/templates/elysia/src/questpie/server/.generated/entities.gen.ts +84 -0
  21. package/templates/elysia/src/questpie/server/.generated/factories.ts +65 -0
  22. package/templates/elysia/src/questpie/server/.generated/index.ts +131 -0
  23. package/templates/elysia/src/questpie/server/.generated/names.gen.ts +25 -0
  24. package/templates/elysia/src/questpie/server/app.ts +10 -0
  25. package/templates/elysia/src/questpie/server/collections/index.ts +1 -0
  26. package/templates/elysia/src/questpie/server/collections/posts.collection.ts +10 -0
  27. package/templates/elysia/src/questpie/server/config/auth.ts +8 -0
  28. package/templates/elysia/src/questpie/server/config/openapi.ts +10 -0
  29. package/templates/elysia/src/questpie/server/globals/index.ts +1 -0
  30. package/templates/elysia/src/questpie/server/globals/site-settings.global.ts +10 -0
  31. package/templates/elysia/src/questpie/server/modules.ts +8 -0
  32. package/templates/elysia/src/questpie/server/questpie.config.ts +21 -0
  33. package/templates/elysia/tsconfig.json +28 -0
  34. package/templates/hono/AGENTS.md +56 -0
  35. package/templates/hono/CLAUDE.md +39 -0
  36. package/templates/hono/Dockerfile +24 -0
  37. package/templates/hono/README.md +148 -0
  38. package/templates/hono/docker/init-extensions.sql +11 -0
  39. package/templates/hono/docker-compose.yml +21 -0
  40. package/templates/hono/env.example +16 -0
  41. package/templates/hono/gitignore +6 -0
  42. package/templates/hono/package.json +47 -0
  43. package/templates/hono/questpie.config.ts +12 -0
  44. package/templates/hono/src/index.ts +30 -0
  45. package/templates/hono/src/lib/auth-client.ts +32 -0
  46. package/templates/hono/src/lib/client.ts +13 -0
  47. package/templates/hono/src/lib/env.ts +24 -0
  48. package/templates/hono/src/lib/query-client.ts +18 -0
  49. package/templates/hono/src/lib/query.ts +18 -0
  50. package/templates/hono/src/questpie/server/.generated/context.gen.ts +200 -0
  51. package/templates/hono/src/questpie/server/.generated/entities.gen.ts +84 -0
  52. package/templates/hono/src/questpie/server/.generated/factories.ts +65 -0
  53. package/templates/hono/src/questpie/server/.generated/index.ts +131 -0
  54. package/templates/hono/src/questpie/server/.generated/names.gen.ts +25 -0
  55. package/templates/hono/src/questpie/server/app.ts +10 -0
  56. package/templates/hono/src/questpie/server/collections/index.ts +1 -0
  57. package/templates/hono/src/questpie/server/collections/posts.collection.ts +10 -0
  58. package/templates/hono/src/questpie/server/config/auth.ts +8 -0
  59. package/templates/hono/src/questpie/server/config/openapi.ts +10 -0
  60. package/templates/hono/src/questpie/server/globals/index.ts +1 -0
  61. package/templates/hono/src/questpie/server/globals/site-settings.global.ts +10 -0
  62. package/templates/hono/src/questpie/server/modules.ts +8 -0
  63. package/templates/hono/src/questpie/server/questpie.config.ts +21 -0
  64. package/templates/hono/tsconfig.json +28 -0
  65. package/templates/next/AGENTS.md +55 -0
  66. package/templates/next/CLAUDE.md +39 -0
  67. package/templates/next/Dockerfile +25 -0
  68. package/templates/next/README.md +148 -0
  69. package/templates/next/components.json +22 -0
  70. package/templates/next/docker/init-extensions.sql +11 -0
  71. package/templates/next/docker-compose.yml +21 -0
  72. package/templates/next/env.example +16 -0
  73. package/templates/next/gitignore +10 -0
  74. package/templates/next/next-env.d.ts +5 -0
  75. package/templates/next/next.config.ts +20 -0
  76. package/templates/next/package.json +54 -0
  77. package/templates/next/postcss.config.mjs +8 -0
  78. package/templates/next/public/.gitkeep +0 -0
  79. package/templates/next/questpie.config.ts +12 -0
  80. package/templates/next/src/app/admin/[[...all]]/page.tsx +34 -0
  81. package/templates/next/src/app/admin/admin.css +4 -0
  82. package/templates/next/src/app/admin/layout.tsx +63 -0
  83. package/templates/next/src/app/api/[...all]/route.ts +24 -0
  84. package/templates/next/src/app/layout.tsx +24 -0
  85. package/templates/next/src/app/not-found.tsx +18 -0
  86. package/templates/next/src/app/page.tsx +74 -0
  87. package/templates/next/src/app/providers.tsx +11 -0
  88. package/templates/next/src/lib/auth-client.ts +12 -0
  89. package/templates/next/src/lib/client.ts +13 -0
  90. package/templates/next/src/lib/env.ts +24 -0
  91. package/templates/next/src/lib/query-client.ts +18 -0
  92. package/templates/next/src/lib/query.ts +18 -0
  93. package/templates/next/src/questpie/admin/.generated/client.ts +13 -0
  94. package/templates/next/src/questpie/admin/admin.ts +9 -0
  95. package/templates/next/src/questpie/admin/modules.ts +3 -0
  96. package/templates/next/src/questpie/server/.generated/context.gen.ts +204 -0
  97. package/templates/next/src/questpie/server/.generated/entities.gen.ts +100 -0
  98. package/templates/next/src/questpie/server/.generated/factories.ts +204 -0
  99. package/templates/next/src/questpie/server/.generated/index.ts +139 -0
  100. package/templates/next/src/questpie/server/.generated/names.gen.ts +31 -0
  101. package/templates/next/src/questpie/server/app.ts +10 -0
  102. package/templates/next/src/questpie/server/collections/index.ts +1 -0
  103. package/templates/next/src/questpie/server/collections/posts.collection.ts +58 -0
  104. package/templates/next/src/questpie/server/config/admin.ts +80 -0
  105. package/templates/next/src/questpie/server/config/auth.ts +8 -0
  106. package/templates/next/src/questpie/server/config/openapi.ts +10 -0
  107. package/templates/next/src/questpie/server/globals/index.ts +1 -0
  108. package/templates/next/src/questpie/server/globals/site-settings.global.ts +19 -0
  109. package/templates/next/src/questpie/server/modules.ts +9 -0
  110. package/templates/next/src/questpie/server/questpie.config.ts +21 -0
  111. package/templates/next/src/styles.css +125 -0
  112. package/templates/next/tsconfig.json +37 -0
  113. package/templates/tanstack-start/AGENTS.md +35 -607
  114. package/templates/tanstack-start/CLAUDE.md +26 -134
  115. package/templates/tanstack-start/README.md +13 -1
  116. package/templates/tanstack-start/docker/init-extensions.sql +11 -0
  117. package/templates/tanstack-start/docker-compose.yml +1 -0
  118. package/templates/tanstack-start/src/lib/auth-client.ts +1 -1
  119. package/templates/tanstack-start/src/lib/client.ts +1 -1
  120. package/templates/tanstack-start/src/lib/query.ts +18 -0
  121. package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
  122. package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
  123. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +1 -1
  124. package/templates/tanstack-start/src/routes/__root.tsx +31 -1
  125. package/templates/tanstack-start/src/routes/api/$.ts +1 -1
  126. package/templates/tanstack-start/src/routes/index.tsx +97 -0
  127. package/skills/questpie/AGENTS.md +0 -2871
  128. package/skills/questpie/SKILL.md +0 -293
  129. package/skills/questpie/coverage.json +0 -213
  130. package/skills/questpie/references/auth.md +0 -236
  131. package/skills/questpie/references/business-logic.md +0 -620
  132. package/skills/questpie/references/codegen-plugin-api.md +0 -382
  133. package/skills/questpie/references/crud-api.md +0 -580
  134. package/skills/questpie/references/data-modeling.md +0 -509
  135. package/skills/questpie/references/extend.md +0 -584
  136. package/skills/questpie/references/field-types.md +0 -398
  137. package/skills/questpie/references/infrastructure-adapters.md +0 -720
  138. package/skills/questpie/references/mcp.md +0 -147
  139. package/skills/questpie/references/multi-tenancy.md +0 -363
  140. package/skills/questpie/references/production.md +0 -640
  141. package/skills/questpie/references/query-operators.md +0 -125
  142. package/skills/questpie/references/quickstart.md +0 -562
  143. package/skills/questpie/references/rules.md +0 -454
  144. package/skills/questpie/references/sandbox.md +0 -110
  145. package/skills/questpie/references/tanstack-query.md +0 -543
  146. package/skills/questpie/references/type-inference.md +0 -167
  147. package/skills/questpie/references/workflows.md +0 -155
  148. package/skills/questpie-admin/AGENTS.md +0 -1515
  149. package/skills/questpie-admin/SKILL.md +0 -443
  150. package/skills/questpie-admin/references/blocks.md +0 -331
  151. package/skills/questpie-admin/references/custom-ui.md +0 -305
  152. package/skills/questpie-admin/references/views.md +0 -449
@@ -1,443 +0,0 @@
1
- ---
2
- name: questpie-admin
3
- description: QUESTPIE admin panel — setup, branding, theming, sidebar, dashboard, views, blocks, custom fields, media, localization, live preview, auth, dark mode, CSS variables. Use when building or customizing the QUESTPIE admin UI.
4
- license: MIT
5
- metadata:
6
- author: questpie
7
- version: "3.0.0"
8
- ---
9
-
10
- # QUESTPIE Admin Panel
11
-
12
- The QUESTPIE admin panel is a **projection of your server schema** — not the framework itself. It reads collections, globals, and config via introspection and generates a full admin interface. Your backend works without it.
13
-
14
- ## Reference Topics
15
-
16
- | Topic | File | Covers |
17
- | --------- | ------------------------- | -------------------------------------------------------------------------------------- |
18
- | Views | `references/views.md` | List views, form views, dashboard, sidebar, filters, bulk actions, visibility, history |
19
- | Blocks | `references/blocks.md` | Block definitions, fields, prefetch, renderers, block picker |
20
- | Custom UI | `references/custom-ui.md` | Custom fields, custom views, registries, reactive fields, widgets |
21
-
22
- ## Full Compiled Document
23
-
24
- For the complete admin reference with all topics expanded: `AGENTS.md`
25
-
26
- ## Tech Stack
27
-
28
- - **React** + **Tailwind CSS v4** + **shadcn** components
29
- - **@base-ui/react** primitives (NOT @radix-ui)
30
- - **@iconify/react** with Phosphor icon set (`ph:icon-name`)
31
- - **sonner** for toasts — `toast.error()`, `toast.success()`
32
- - QUESTPIE Neutral Design: flat surfaces, soft neutral geometry,
33
- tokenized radius, and restrained floating shadows
34
-
35
- ## Setup
36
-
37
- ### 1. Install
38
-
39
- ```bash
40
- bun add @questpie/admin
41
- ```
42
-
43
- ### 2. Runtime Config
44
-
45
- ```ts title="questpie.config.ts"
46
- import { runtimeConfig } from "questpie/app";
47
- export default runtimeConfig({
48
- app: { url: process.env.APP_URL || "http://localhost:3000" },
49
- db: { url: process.env.DATABASE_URL },
50
- secret: process.env.APP_SECRET,
51
- });
52
- ```
53
-
54
- The admin module contributes the codegen plugin automatically. It discovers `config/admin.ts`, `blocks/`, views, components, and admin client modules.
55
-
56
- ### 3. Modules
57
-
58
- ```ts title="modules.ts"
59
- import { adminModule } from "@questpie/admin/modules/admin";
60
- import { auditModule } from "@questpie/admin/modules/audit";
61
-
62
- export default [adminModule, auditModule] as const;
63
- ```
64
-
65
- | Module | Provides |
66
- | ------------- | ------------------------------------- |
67
- | `adminModule` | User collection, auth pages, admin UI |
68
- | `auditModule` | Audit log collection, timeline widget |
69
-
70
- ### Auth/User Contract - Critical
71
-
72
- `adminModule` includes the starter auth model and owns the canonical Better Auth `user` collection shape used by admin setup and login guards. That contract includes `user.role` with at least `admin` and `user` values. The built-in setup route checks for `role = "admin"`, and the admin `AuthGuard` expects `session.user.role === "admin"`.
73
-
74
- Do not create a replacement `collection("user")` from scratch in an app that uses `adminModule`. If the app needs to customize the user admin UI or add fields, merge the starter user collection and extend it:
75
-
76
- ```ts title="collections/user.ts"
77
- import { starterModule } from "questpie/app";
78
- import { collection } from "#questpie/factories";
79
-
80
- export default collection("user")
81
- .merge(starterModule.collections.user)
82
- .fields(({ f }) => ({
83
- // add app-specific user fields here
84
- internalNotes: f.textarea(),
85
- }));
86
- ```
87
-
88
- App-specific authorization tables are fine, but they must not replace or remove the admin user contract unless the app also replaces the built-in admin setup route and auth guard.
89
-
90
- ### 4. Admin Config
91
-
92
- ```ts title="config/admin.ts"
93
- import { adminConfig } from "#questpie/factories";
94
-
95
- export default adminConfig({
96
- branding: {
97
- name: { en: "My App Admin" },
98
- },
99
- sidebar: {
100
- sections: [
101
- { id: "overview", title: { en: "Overview" } },
102
- { id: "content", title: { en: "Content" } },
103
- ],
104
- items: [
105
- {
106
- sectionId: "overview",
107
- type: "link",
108
- label: { en: "Dashboard" },
109
- href: "/admin",
110
- icon: { type: "icon", props: { name: "ph:house" } },
111
- },
112
- {
113
- sectionId: "content",
114
- type: "collection",
115
- collection: "posts",
116
- },
117
- ],
118
- },
119
- });
120
- ```
121
-
122
- ### 5. Codegen
123
-
124
- ```bash
125
- bunx questpie generate
126
- ```
127
-
128
- ### 6. Mount the Admin
129
-
130
- ```ts title="routes/admin/$.tsx"
131
- import { AdminRouter } from "@questpie/admin/client";
132
- import { admin } from "@/questpie/admin/admin";
133
-
134
- export default function AdminPage() {
135
- return <AdminRouter admin={admin} />;
136
- }
137
- ```
138
-
139
- The admin client config is auto-generated by codegen at `admin/.generated/client.ts`. No manual builder setup needed.
140
-
141
- ## Branding
142
-
143
- ```ts title="config/admin.ts"
144
- import { adminConfig } from "#questpie/factories";
145
-
146
- export default adminConfig({
147
- branding: {
148
- name: { en: "Barbershop Control", sk: "Riadenie barbershopu" },
149
- },
150
- });
151
- ```
152
-
153
- | Option | Type | Description |
154
- | ------ | ---------------- | -------------------------------- |
155
- | `name` | `string \| i18n` | App name shown in sidebar header |
156
- | `logo` | `string` | Logo URL or path |
157
-
158
- ## Theming (CSS Variables)
159
-
160
- The admin uses CSS variables for all theming. Override them in your own CSS file.
161
-
162
- The full source of truth is `packages/admin/DESIGN.md`. Key defaults:
163
-
164
- | Role | Dark | Light |
165
- | ------------- | --------- | --------- |
166
- | Background | `#121212` | `#fafafa` |
167
- | Foreground | `#ececec` | `#1c1c1c` |
168
- | Card | `#1b1b1b` | `#ffffff` |
169
- | Surface high | `#2a2a2a` | `#e8e8e8` |
170
- | Border | `#343434` | `#e2e2e2` |
171
- | Border subtle | `#262626` | `#ebebeb` |
172
- | Brand primary | `#b700ff` | `#b700ff` |
173
-
174
- | Token | Default | Use |
175
- | ------------------------ | ------- | ------------------------------------------- |
176
- | `--control-radius-inner` | `8px` | Icon buttons/actions nested inside controls |
177
- | `--control-radius` | `12px` | Inputs, selects, buttons, compact controls |
178
- | `--surface-radius` | `14px` | Cards, panels, grouped fields, docs blocks |
179
- | `--floating-radius` | `14px` | Menus, popovers, dialogs, command panels |
180
-
181
- ### Typography
182
-
183
- | Variable | Value |
184
- | ------------- | ------------------------------------------------------------------- |
185
- | `--font-sans` | `"Geist Variable"` — UI, prose, headings, labels, navigation |
186
- | `--font-mono` | `"JetBrains Mono Variable"` — code, file paths, commands, IDs |
187
-
188
- ### Sidebar Variables
189
-
190
- Separate tokens for independent sidebar theming: `--sidebar`, `--sidebar-foreground`, `--sidebar-primary`, `--sidebar-accent`, `--sidebar-border`, `--sidebar-ring`.
191
-
192
- ### Custom Theme
193
-
194
- 1. Copy the admin CSS file
195
- 2. Change variable values
196
- 3. Import your copy instead
197
- 4. Zero component changes needed
198
-
199
- ## Content Localization
200
-
201
- When collections have `.localized()` fields, the admin shows a locale switcher:
202
-
203
- ```ts title="config/app.ts"
204
- import { appConfig } from "questpie/app";
205
- export default appConfig({
206
- locale: {
207
- locales: [
208
- { code: "en", label: { en: "English" }, flagCountryCode: "gb" },
209
- { code: "sk", label: { en: "Slovak" } },
210
- ],
211
- defaultLocale: "en",
212
- },
213
- });
214
- ```
215
-
216
- The admin tracks content locale separately from UI locale. Only localized field values change when switching.
217
-
218
- ## Media & Uploads
219
-
220
- ```ts
221
- avatar: f.upload({
222
- to: "assets",
223
- mimeTypes: ["image/*"],
224
- maxSize: 5_000_000,
225
- }),
226
- ```
227
-
228
- The admin renders drag-and-drop upload, image preview, file info, and remove button.
229
-
230
- ## Live Preview
231
-
232
- Live Preview is one system: the existing collection `FormView`, Preview button, `LivePreviewMode`, and frontend iframe. Preserve the normal form lifecycle. Do not introduce a separate visual-edit form API, a second default form view, or a parallel preview surface.
233
-
234
- The admin form is authoritative. The iframe mirrors form state through `postMessage`, supports field/block focus, and may request inline scalar edits. Persistence still goes through existing save, autosave, Cmd+S, history, workflow, locks, and actions.
235
-
236
- ### Server Config
237
-
238
- Add `.preview()` to a collection to enable split-screen editing:
239
-
240
- ```ts title="collections/pages.ts"
241
- export const pages = collection("pages")
242
- .fields(({ f }) => ({
243
- title: f.text().required().localized(),
244
- slug: f.text().required(),
245
- content: f.blocks().localized(),
246
- }))
247
- .preview({
248
- enabled: true,
249
- position: "right",
250
- defaultWidth: 50,
251
- url: ({ record }) => {
252
- const slug = record.slug as string;
253
- return slug === "home" ? "/?preview=true" : `/${slug}?preview=true`;
254
- },
255
- });
256
- ```
257
-
258
- Preview opens the existing split-screen editor. Patches and refresh/resync messages update the iframe mirror; save/autosave still writes through the form.
259
-
260
- ### Prepare a Frontend Page
261
-
262
- Use exported APIs only: `useCollectionPreview`, `PreviewProvider`, `PreviewField`, and `BlockRenderer`.
263
-
264
- Checklist:
265
-
266
- 1. Configure `.preview({ url })` on the collection.
267
- 2. Load the same record shape the page normally renders.
268
- 3. For workflow-published pages, public reads use `stage: "published"`; if the public client/HTTP API is exposed, anonymous read access also checks `input?.stage === "published"`. Authorized preview/draft reads can load the working record.
269
- 4. Call `useCollectionPreview({ initialData, onRefresh })` in the page renderer.
270
- 5. Wrap the visual output in `PreviewProvider`.
271
- 6. Render from `preview.data`, not the original loader object.
272
- 7. Wrap editable scalar text with `PreviewField field="..." editable="text" | "textarea"`.
273
- 8. Render block content with `BlockRenderer`; pass `selectedBlockId` and `onBlockClick`.
274
- 9. Keep add/remove/reorder/nesting block operations in the existing block editor.
275
-
276
- ```tsx
277
- import {
278
- BlockRenderer,
279
- PreviewField,
280
- PreviewProvider,
281
- useCollectionPreview,
282
- } from "@questpie/admin/client";
283
- import admin from "@/questpie/admin/.generated/client";
284
-
285
- function PagePreview({ page }) {
286
- const router = useRouter();
287
- const preview = useCollectionPreview({
288
- initialData: page,
289
- onRefresh: () => router.invalidate(),
290
- });
291
-
292
- return (
293
- <PreviewProvider preview={preview}>
294
- <main className={preview.isPreviewMode ? "questpie-preview" : undefined}>
295
- <PreviewField field="title" editable="text" as="h1">
296
- {preview.data.title}
297
- </PreviewField>
298
-
299
- <BlockRenderer
300
- content={preview.data.content}
301
- data={preview.data.content?._data}
302
- renderers={admin.blocks}
303
- selectedBlockId={preview.selectedBlockId}
304
- onBlockClick={
305
- preview.isPreviewMode ? preview.handleBlockClick : undefined
306
- }
307
- />
308
- </main>
309
- </PreviewProvider>
310
- );
311
- }
312
- ```
313
-
314
- ### Key Principles
315
-
316
- - Keep `FormView`, the Preview button, and `LivePreviewMode`
317
- - Never add a separate visual-edit form API, a second default form view, or parallel preview API names
318
- - Preserve save/autosave/Cmd+S/history/workflow/locks/actions
319
- - `useCollectionPreview` handles preview mode, mirrored data, refresh/resync, and focus state
320
- - `PreviewProvider` supplies preview context to `PreviewField`
321
- - `PreviewField` annotates scalar fields and can opt into inline editing with `editable`
322
- - `BlockRenderer` preserves block IDs and block scopes for block annotations
323
- - Use `BlockScopeProvider` only for custom/manual block rendering outside `BlockRenderer`
324
- - Validate all iframe messages before updating form state
325
-
326
- ## History & Versions
327
-
328
- Enable `auditModule` for activity timeline. Enable versioning on collections for snapshot restore:
329
-
330
- ```ts
331
- export const pages = collection("pages")
332
- .fields(({ f }) => ({ ... }))
333
- .options({ versioning: true });
334
- ```
335
-
336
- ## Scope (Multi-Tenancy)
337
-
338
- The admin provides scope primitives for multi-tenant applications. Import from `@questpie/admin/client`.
339
-
340
- ### ScopeProvider
341
-
342
- Wraps the admin to enable scope selection. Manages scope ID in React state and persists to localStorage.
343
-
344
- ```tsx
345
- import { ScopeProvider } from "@questpie/admin/client";
346
-
347
- <ScopeProvider
348
- headerName="x-selected-workspace" // HTTP header for scope ID
349
- storageKey="admin-workspace" // localStorage key
350
- defaultScope={null} // default value
351
- >
352
- <AdminLayout>...</AdminLayout>
353
- </ScopeProvider>;
354
- ```
355
-
356
- ### ScopePicker
357
-
358
- Dropdown for selecting the current scope. Place in sidebar via `slots.afterBrand`:
359
-
360
- ```tsx
361
- import { ScopePicker } from "@questpie/admin/client";
362
-
363
- <AdminLayout
364
- admin={admin}
365
- basePath="/admin"
366
- slots={{
367
- afterBrand: (
368
- <div className="px-3 py-2 border-b">
369
- <ScopePicker
370
- collection="workspaces"
371
- labelField="name"
372
- allowClear
373
- compact
374
- />
375
- </div>
376
- ),
377
- }}
378
- />;
379
- ```
380
-
381
- Three data sources: `collection` (queries a collection), `options` (static array), `loadOptions` (async function).
382
-
383
- ### useScopedFetch / createScopedFetch
384
-
385
- Inject scope header into all API calls:
386
-
387
- ```tsx
388
- import { useScopedFetch, createScopedFetch } from "@questpie/admin/client";
389
-
390
- // React hook
391
- const scopedFetch = useScopedFetch();
392
- const client = useMemo(
393
- () => createClient({ baseURL: "/api", fetch: scopedFetch }),
394
- [scopedFetch],
395
- );
396
-
397
- // Non-React
398
- const scopedFetch = createScopedFetch("x-selected-workspace", () =>
399
- getScopeId(),
400
- );
401
- ```
402
-
403
- ### useScope / useScopeSafe
404
-
405
- Access current scope state in any component:
406
-
407
- ```tsx
408
- import { useScope, useScopeSafe } from "@questpie/admin/client";
409
-
410
- const { scopeId, setScope, clearScope, headerName } = useScope(); // throws outside ScopeProvider
411
- const scope = useScopeSafe(); // returns null outside ScopeProvider
412
- ```
413
-
414
- For the full server-side setup (context resolver, type augmentation, access rules), see the `questpie` skill's `references/multi-tenancy.md`.
415
-
416
- ## Common Mistakes
417
-
418
- 1. **CRITICAL: Using `asChild` prop** — QUESTPIE admin uses `@base-ui/react`, which uses the `render` prop. `asChild` is a Radix pattern and does NOT work here.
419
-
420
- ```tsx
421
- // WRONG
422
- <DialogTrigger asChild><Button>Open</Button></DialogTrigger>
423
- // CORRECT
424
- <DialogTrigger render={<Button>Open</Button>} />
425
- ```
426
-
427
- 2. **CRITICAL: Importing from `@radix-ui/*`** — use `@base-ui/react` instead.
428
-
429
- 3. **HIGH: Using `@phosphor-icons/react`** — use `@iconify/react` with `ph:` prefix.
430
-
431
- ```tsx
432
- // WRONG
433
- import { CaretDown } from "@phosphor-icons/react";
434
- // CORRECT
435
- import { Icon } from "@iconify/react";
436
- <Icon icon="ph:caret-down" width={16} height={16} />;
437
- ```
438
-
439
- 4. **HIGH: Using lucide-react icons** — use `@iconify/react` with Phosphor icon set.
440
-
441
- 5. **MEDIUM: Custom `<button>` or `<div>` instead of shadcn components** — use `<Button>`, `<Card>`, etc.
442
-
443
- 6. **MEDIUM: `console.error` for user errors** — use `toast.error()` from `sonner`.