create-questpie 2.0.3 → 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 (153) hide show
  1. package/dist/index.mjs +544 -87
  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 -600
  114. package/templates/tanstack-start/CLAUDE.md +26 -127
  115. package/templates/tanstack-start/README.md +20 -7
  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/package.json +1 -0
  119. package/templates/tanstack-start/src/lib/auth-client.ts +1 -1
  120. package/templates/tanstack-start/src/lib/client.ts +1 -1
  121. package/templates/tanstack-start/src/lib/query.ts +18 -0
  122. package/templates/tanstack-start/src/questpie/admin/modules.ts +3 -1
  123. package/templates/tanstack-start/src/questpie/server/.generated/factories.ts +10 -9
  124. package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
  125. package/templates/tanstack-start/src/questpie/server/config/auth.ts +1 -1
  126. package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
  127. package/templates/tanstack-start/src/questpie/server/modules.ts +4 -5
  128. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +3 -2
  129. package/templates/tanstack-start/src/routes/__root.tsx +31 -1
  130. package/templates/tanstack-start/src/routes/api/$.ts +2 -3
  131. package/templates/tanstack-start/src/routes/index.tsx +97 -0
  132. package/templates/tanstack-start/vite.config.ts +2 -2
  133. package/skills/questpie/AGENTS.md +0 -2670
  134. package/skills/questpie/SKILL.md +0 -260
  135. package/skills/questpie/references/auth.md +0 -121
  136. package/skills/questpie/references/business-logic.md +0 -550
  137. package/skills/questpie/references/codegen-plugin-api.md +0 -382
  138. package/skills/questpie/references/crud-api.md +0 -378
  139. package/skills/questpie/references/data-modeling.md +0 -493
  140. package/skills/questpie/references/extend.md +0 -557
  141. package/skills/questpie/references/field-types.md +0 -386
  142. package/skills/questpie/references/infrastructure-adapters.md +0 -545
  143. package/skills/questpie/references/multi-tenancy.md +0 -364
  144. package/skills/questpie/references/production.md +0 -475
  145. package/skills/questpie/references/query-operators.md +0 -125
  146. package/skills/questpie/references/quickstart.md +0 -564
  147. package/skills/questpie/references/rules.md +0 -389
  148. package/skills/questpie/references/tanstack-query.md +0 -520
  149. package/skills/questpie-admin/AGENTS.md +0 -1508
  150. package/skills/questpie-admin/SKILL.md +0 -436
  151. package/skills/questpie-admin/references/blocks.md +0 -331
  152. package/skills/questpie-admin/references/custom-ui.md +0 -305
  153. package/skills/questpie-admin/references/views.md +0 -449
@@ -1,436 +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
- - Brutalist flat design: `--radius: 0px`, no shadows
33
-
34
- ## Setup
35
-
36
- ### 1. Install
37
-
38
- ```bash
39
- bun add @questpie/admin
40
- ```
41
-
42
- ### 2. Runtime Config
43
-
44
- ```ts title="questpie.config.ts"
45
- import { runtimeConfig } from "questpie";
46
-
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, auditModule } from "@questpie/admin/server";
60
-
61
- export default [adminModule, auditModule] as const;
62
- ```
63
-
64
- | Module | Provides |
65
- | ------------- | ------------------------------------- |
66
- | `adminModule` | User collection, auth pages, admin UI |
67
- | `auditModule` | Audit log collection, timeline widget |
68
-
69
- ### 4. Admin Config
70
-
71
- ```ts title="config/admin.ts"
72
- import { adminConfig } from "#questpie/factories";
73
-
74
- export default adminConfig({
75
- branding: {
76
- name: { en: "My App Admin" },
77
- },
78
- sidebar: {
79
- sections: [
80
- { id: "overview", title: { en: "Overview" } },
81
- { id: "content", title: { en: "Content" } },
82
- ],
83
- items: [
84
- {
85
- sectionId: "overview",
86
- type: "link",
87
- label: { en: "Dashboard" },
88
- href: "/admin",
89
- icon: { type: "icon", props: { name: "ph:house" } },
90
- },
91
- {
92
- sectionId: "content",
93
- type: "collection",
94
- collection: "posts",
95
- },
96
- ],
97
- },
98
- });
99
- ```
100
-
101
- ### 5. Codegen
102
-
103
- ```bash
104
- bunx questpie generate
105
- ```
106
-
107
- ### 6. Mount the Admin
108
-
109
- ```ts title="routes/admin/$.tsx"
110
- import { AdminRouter } from "@questpie/admin/client";
111
- import { admin } from "@/questpie/admin/admin";
112
-
113
- export default function AdminPage() {
114
- return <AdminRouter admin={admin} />;
115
- }
116
- ```
117
-
118
- The admin client config is auto-generated by codegen at `admin/.generated/client.ts`. No manual builder setup needed.
119
-
120
- ## Branding
121
-
122
- ```ts title="config/admin.ts"
123
- import { adminConfig } from "#questpie/factories";
124
-
125
- export default adminConfig({
126
- branding: {
127
- name: { en: "Barbershop Control", sk: "Riadenie barbershopu" },
128
- },
129
- });
130
- ```
131
-
132
- | Option | Type | Description |
133
- | ------ | ---------------- | -------------------------------- |
134
- | `name` | `string \| i18n` | App name shown in sidebar header |
135
- | `logo` | `string` | Logo URL or path |
136
-
137
- ## Theming (CSS Variables)
138
-
139
- The admin uses CSS variables for all theming. Override them in your own CSS file.
140
-
141
- ### Light Theme (`:root`)
142
-
143
- | Variable | Default | Purpose |
144
- | ---------------------- | --------- | -------------------------------- |
145
- | `--background` | `#FFFFFF` | Page background |
146
- | `--foreground` | `#0A0A0A` | Primary text |
147
- | `--card` | `#F8F8F8` | Cards, panels, sidebar |
148
- | `--popover` | `#FFFFFF` | Dropdowns, tooltips, dialogs |
149
- | `--muted` | `#F0F0F0` | Hover states, table headers |
150
- | `--muted-foreground` | `#666666` | Secondary text, placeholders |
151
- | `--primary` | `#B700FF` | Brand accent (CTAs, focus rings) |
152
- | `--primary-foreground` | `#FFFFFF` | Text on primary backgrounds |
153
- | `--destructive` | `#FF3D57` | Errors, delete actions |
154
- | `--success` | `#00E676` | Positive states |
155
- | `--warning` | `#FFB300` | Caution states |
156
- | `--info` | `#40C4FF` | Informational emphasis |
157
- | `--border` | `#E0E0E0` | All structural borders |
158
- | `--ring` | `#B700FF` | Focus ring color |
159
- | `--radius` | `0px` | Border radius (0 = brutalist) |
160
-
161
- ### Dark Theme (`.dark` class)
162
-
163
- Dark mode uses the `.dark` class on the root element. Key overrides:
164
-
165
- | Variable | Dark Value |
166
- | -------------- | ---------- |
167
- | `--background` | `#0A0A0A` |
168
- | `--foreground` | `#FFFFFF` |
169
- | `--card` | `#111111` |
170
- | `--border` | `#333333` |
171
- | `--muted` | `#1A1A1A` |
172
-
173
- ### Typography
174
-
175
- | Variable | Value |
176
- | ------------- | ------------------------------------------------------------------- |
177
- | `--font-sans` | `"Geist Variable"` — body text, descriptions |
178
- | `--font-mono` | `"JetBrains Mono Variable"` — UI chrome: nav, buttons, tabs, badges |
179
-
180
- ### Sidebar Variables
181
-
182
- Separate tokens for independent sidebar theming: `--sidebar`, `--sidebar-foreground`, `--sidebar-primary`, `--sidebar-accent`, `--sidebar-border`, `--sidebar-ring`.
183
-
184
- ### Custom Theme
185
-
186
- 1. Copy the admin CSS file
187
- 2. Change variable values
188
- 3. Import your copy instead
189
- 4. Zero component changes needed
190
-
191
- ## Content Localization
192
-
193
- When collections have `.localized()` fields, the admin shows a locale switcher:
194
-
195
- ```ts title="config/app.ts"
196
- import { appConfig } from "questpie";
197
-
198
- export default appConfig({
199
- locale: {
200
- locales: [
201
- { code: "en", label: { en: "English" }, flagCountryCode: "gb" },
202
- { code: "sk", label: { en: "Slovak" } },
203
- ],
204
- defaultLocale: "en",
205
- },
206
- });
207
- ```
208
-
209
- The admin tracks content locale separately from UI locale. Only localized field values change when switching.
210
-
211
- ## Media & Uploads
212
-
213
- ```ts
214
- avatar: f.upload({
215
- to: "assets",
216
- mimeTypes: ["image/*"],
217
- maxSize: 5_000_000,
218
- }),
219
- ```
220
-
221
- The admin renders drag-and-drop upload, image preview, file info, and remove button.
222
-
223
- ## Live Preview
224
-
225
- 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.
226
-
227
- 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.
228
-
229
- ### Server Config
230
-
231
- Add `.preview()` to a collection to enable split-screen editing:
232
-
233
- ```ts title="collections/pages.ts"
234
- export const pages = collection("pages")
235
- .fields(({ f }) => ({
236
- title: f.text().required().localized(),
237
- slug: f.text().required(),
238
- content: f.blocks().localized(),
239
- }))
240
- .preview({
241
- enabled: true,
242
- position: "right",
243
- defaultWidth: 50,
244
- url: ({ record }) => {
245
- const slug = record.slug as string;
246
- return slug === "home" ? "/?preview=true" : `/${slug}?preview=true`;
247
- },
248
- });
249
- ```
250
-
251
- Preview opens the existing split-screen editor. Patches and refresh/resync messages update the iframe mirror; save/autosave still writes through the form.
252
-
253
- ### Prepare a Frontend Page
254
-
255
- Use exported APIs only: `useCollectionPreview`, `PreviewProvider`, `PreviewField`, and `BlockRenderer`.
256
-
257
- Checklist:
258
-
259
- 1. Configure `.preview({ url })` on the collection.
260
- 2. Load the same record shape the page normally renders.
261
- 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.
262
- 4. Call `useCollectionPreview({ initialData, onRefresh })` in the page renderer.
263
- 5. Wrap the visual output in `PreviewProvider`.
264
- 6. Render from `preview.data`, not the original loader object.
265
- 7. Wrap editable scalar text with `PreviewField field="..." editable="text" | "textarea"`.
266
- 8. Render block content with `BlockRenderer`; pass `selectedBlockId` and `onBlockClick`.
267
- 9. Keep add/remove/reorder/nesting block operations in the existing block editor.
268
-
269
- ```tsx
270
- import {
271
- BlockRenderer,
272
- PreviewField,
273
- PreviewProvider,
274
- useCollectionPreview,
275
- } from "@questpie/admin/client";
276
- import admin from "@/questpie/admin/.generated/client";
277
-
278
- function PagePreview({ page }) {
279
- const router = useRouter();
280
- const preview = useCollectionPreview({
281
- initialData: page,
282
- onRefresh: () => router.invalidate(),
283
- });
284
-
285
- return (
286
- <PreviewProvider preview={preview}>
287
- <main className={preview.isPreviewMode ? "questpie-preview" : undefined}>
288
- <PreviewField field="title" editable="text" as="h1">
289
- {preview.data.title}
290
- </PreviewField>
291
-
292
- <BlockRenderer
293
- content={preview.data.content}
294
- data={preview.data.content?._data}
295
- renderers={admin.blocks}
296
- selectedBlockId={preview.selectedBlockId}
297
- onBlockClick={
298
- preview.isPreviewMode ? preview.handleBlockClick : undefined
299
- }
300
- />
301
- </main>
302
- </PreviewProvider>
303
- );
304
- }
305
- ```
306
-
307
- ### Key Principles
308
-
309
- - Keep `FormView`, the Preview button, and `LivePreviewMode`
310
- - Never add a separate visual-edit form API, a second default form view, or parallel preview API names
311
- - Preserve save/autosave/Cmd+S/history/workflow/locks/actions
312
- - `useCollectionPreview` handles preview mode, mirrored data, refresh/resync, and focus state
313
- - `PreviewProvider` supplies preview context to `PreviewField`
314
- - `PreviewField` annotates scalar fields and can opt into inline editing with `editable`
315
- - `BlockRenderer` preserves block IDs and block scopes for block annotations
316
- - Use `BlockScopeProvider` only for custom/manual block rendering outside `BlockRenderer`
317
- - Validate all iframe messages before updating form state
318
-
319
- ## History & Versions
320
-
321
- Enable `auditModule` for activity timeline. Enable versioning on collections for snapshot restore:
322
-
323
- ```ts
324
- export const pages = collection("pages")
325
- .fields(({ f }) => ({ ... }))
326
- .options({ versioning: true });
327
- ```
328
-
329
- ## Scope (Multi-Tenancy)
330
-
331
- The admin provides scope primitives for multi-tenant applications. Import from `@questpie/admin/client`.
332
-
333
- ### ScopeProvider
334
-
335
- Wraps the admin to enable scope selection. Manages scope ID in React state and persists to localStorage.
336
-
337
- ```tsx
338
- import { ScopeProvider } from "@questpie/admin/client";
339
-
340
- <ScopeProvider
341
- headerName="x-selected-workspace" // HTTP header for scope ID
342
- storageKey="admin-workspace" // localStorage key
343
- defaultScope={null} // default value
344
- >
345
- <AdminLayout>...</AdminLayout>
346
- </ScopeProvider>;
347
- ```
348
-
349
- ### ScopePicker
350
-
351
- Dropdown for selecting the current scope. Place in sidebar via `slots.afterBrand`:
352
-
353
- ```tsx
354
- import { ScopePicker } from "@questpie/admin/client";
355
-
356
- <AdminLayout
357
- admin={admin}
358
- basePath="/admin"
359
- slots={{
360
- afterBrand: (
361
- <div className="px-3 py-2 border-b">
362
- <ScopePicker
363
- collection="workspaces"
364
- labelField="name"
365
- allowClear
366
- compact
367
- />
368
- </div>
369
- ),
370
- }}
371
- />;
372
- ```
373
-
374
- Three data sources: `collection` (queries a collection), `options` (static array), `loadOptions` (async function).
375
-
376
- ### useScopedFetch / createScopedFetch
377
-
378
- Inject scope header into all API calls:
379
-
380
- ```tsx
381
- import { useScopedFetch, createScopedFetch } from "@questpie/admin/client";
382
-
383
- // React hook
384
- const scopedFetch = useScopedFetch();
385
- const client = useMemo(
386
- () => createClient({ baseURL: "/api", fetch: scopedFetch }),
387
- [scopedFetch],
388
- );
389
-
390
- // Non-React
391
- const scopedFetch = createScopedFetch("x-selected-workspace", () =>
392
- getScopeId(),
393
- );
394
- ```
395
-
396
- ### useScope / useScopeSafe
397
-
398
- Access current scope state in any component:
399
-
400
- ```tsx
401
- import { useScope, useScopeSafe } from "@questpie/admin/client";
402
-
403
- const { scopeId, setScope, clearScope, headerName } = useScope(); // throws outside ScopeProvider
404
- const scope = useScopeSafe(); // returns null outside ScopeProvider
405
- ```
406
-
407
- For the full server-side setup (context resolver, type augmentation, access rules), see the `questpie` skill's `references/multi-tenancy.md`.
408
-
409
- ## Common Mistakes
410
-
411
- 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.
412
-
413
- ```tsx
414
- // WRONG
415
- <DialogTrigger asChild><Button>Open</Button></DialogTrigger>
416
- // CORRECT
417
- <DialogTrigger render={<Button>Open</Button>} />
418
- ```
419
-
420
- 2. **CRITICAL: Importing from `@radix-ui/*`** — use `@base-ui/react` instead.
421
-
422
- 3. **HIGH: Using `@phosphor-icons/react`** — use `@iconify/react` with `ph:` prefix.
423
-
424
- ```tsx
425
- // WRONG
426
- import { CaretDown } from "@phosphor-icons/react";
427
- // CORRECT
428
- import { Icon } from "@iconify/react";
429
- <Icon icon="ph:caret-down" width={16} height={16} />;
430
- ```
431
-
432
- 4. **HIGH: Using lucide-react icons** — use `@iconify/react` with Phosphor icon set.
433
-
434
- 5. **MEDIUM: Custom `<button>` or `<div>` instead of shadcn components** — use `<Button>`, `<Card>`, etc.
435
-
436
- 6. **MEDIUM: `console.error` for user errors** — use `toast.error()` from `sonner`.