create-questpie 2.0.1 → 2.0.3
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/README.md +10 -6
- package/dist/index.mjs +139 -24
- package/package.json +5 -3
- package/skills/questpie/AGENTS.md +2670 -0
- package/skills/questpie/SKILL.md +260 -0
- package/skills/questpie/references/auth.md +121 -0
- package/skills/questpie/references/business-logic.md +550 -0
- package/skills/questpie/references/codegen-plugin-api.md +382 -0
- package/skills/questpie/references/crud-api.md +378 -0
- package/skills/questpie/references/data-modeling.md +493 -0
- package/skills/questpie/references/extend.md +557 -0
- package/skills/questpie/references/field-types.md +386 -0
- package/skills/questpie/references/infrastructure-adapters.md +545 -0
- package/skills/questpie/references/multi-tenancy.md +364 -0
- package/skills/questpie/references/production.md +475 -0
- package/skills/questpie/references/query-operators.md +125 -0
- package/skills/questpie/references/quickstart.md +564 -0
- package/skills/questpie/references/rules.md +389 -0
- package/skills/questpie/references/tanstack-query.md +520 -0
- package/skills/questpie-admin/AGENTS.md +1508 -0
- package/skills/questpie-admin/SKILL.md +436 -0
- package/skills/questpie-admin/references/blocks.md +331 -0
- package/skills/questpie-admin/references/custom-ui.md +305 -0
- package/skills/questpie-admin/references/views.md +449 -0
- package/templates/tanstack-start/AGENTS.md +17 -13
- package/templates/tanstack-start/CLAUDE.md +15 -12
- package/templates/tanstack-start/README.md +19 -13
- package/templates/tanstack-start/env.example +1 -1
- package/templates/tanstack-start/package.json +20 -6
- package/templates/tanstack-start/src/lib/env.ts +1 -1
- package/templates/tanstack-start/src/lib/query-client.ts +10 -1
- package/templates/tanstack-start/src/questpie/server/config/admin.ts +27 -30
- package/templates/tanstack-start/src/routeTree.gen.ts +138 -0
- package/templates/tanstack-start/src/routes/__root.tsx +0 -2
- package/templates/tanstack-start/src/routes/admin/$.tsx +12 -1
- package/templates/tanstack-start/src/routes/admin/index.tsx +12 -5
- package/templates/tanstack-start/src/routes/admin.tsx +8 -1
- package/templates/tanstack-start/src/tanstack-start.d.ts +1 -0
- package/templates/tanstack-start/src/vite-env.d.ts +1 -0
- package/templates/tanstack-start/vite.config.ts +1 -3
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: questpie-admin/views
|
|
3
|
+
description: QUESTPIE admin views list-view table form-view sections sidebar dashboard widgets filters bulk-actions visibility history versioning sorting search
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# QUESTPIE Admin Views
|
|
7
|
+
|
|
8
|
+
This skill builds on questpie-admin.
|
|
9
|
+
|
|
10
|
+
Views control how data appears in the QUESTPIE admin panel. They are configured **server-side** on collections and globals, then rendered by the admin client via registries.
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
Server Config Admin UI
|
|
14
|
+
.list(({ v }) => v.collectionTable({})) -> Table with columns, sort, search
|
|
15
|
+
.form(({ v, f }) => v.collectionForm({})) -> Form with sections, sidebar, tabs
|
|
16
|
+
sidebar({...}) -> Navigation sidebar
|
|
17
|
+
dashboard({...}) -> Dashboard with widgets
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## List Views
|
|
21
|
+
|
|
22
|
+
Configure table views with `.list()` on a collection.
|
|
23
|
+
|
|
24
|
+
### Basic Table
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
.list(({ v }) => v.collectionTable({}))
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Shows all fields as columns with default rendering.
|
|
31
|
+
|
|
32
|
+
### Custom Columns and Search
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
.list(({ v, f }) =>
|
|
36
|
+
v.collectionTable({
|
|
37
|
+
columns: [f.name, f.email, f.isActive, f.createdAt],
|
|
38
|
+
searchableFields: [f.name, f.email],
|
|
39
|
+
defaultSort: { field: f.createdAt, direction: "desc" },
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Option | Type | Description |
|
|
45
|
+
| ------------------ | ---------------------- | ------------------------------ |
|
|
46
|
+
| `columns` | `Field[]` | Fields to show as columns |
|
|
47
|
+
| `searchableFields` | `Field[]` | Fields included in text search |
|
|
48
|
+
| `defaultSort` | `{ field, direction }` | Default sort order |
|
|
49
|
+
|
|
50
|
+
## Form Views
|
|
51
|
+
|
|
52
|
+
Configure edit forms with `.form()`.
|
|
53
|
+
|
|
54
|
+
### Basic Form
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
.form(({ v, f }) => v.collectionForm({}))
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Renders all fields in a single column.
|
|
61
|
+
|
|
62
|
+
### Sections
|
|
63
|
+
|
|
64
|
+
Group fields into labeled sections with optional grid layout:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
.form(({ v, f }) =>
|
|
68
|
+
v.collectionForm({
|
|
69
|
+
fields: [
|
|
70
|
+
{
|
|
71
|
+
type: "section",
|
|
72
|
+
label: { en: "Contact Information" },
|
|
73
|
+
layout: "grid",
|
|
74
|
+
columns: 2,
|
|
75
|
+
fields: [f.name, f.email, f.phone],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: "section",
|
|
79
|
+
label: { en: "Profile" },
|
|
80
|
+
fields: [f.bio],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
}),
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Option | Type | Description |
|
|
88
|
+
| ------------- | ------------------- | ------------------------------------ |
|
|
89
|
+
| `type` | `"section"` | Required |
|
|
90
|
+
| `label` | `string \| i18n` | Section heading |
|
|
91
|
+
| `description` | `string \| i18n` | Section description |
|
|
92
|
+
| `layout` | `"grid" \| "stack"` | Field layout |
|
|
93
|
+
| `columns` | `number` | Grid columns (with `layout: "grid"`) |
|
|
94
|
+
| `fields` | `Field[]` | Fields in this section |
|
|
95
|
+
|
|
96
|
+
### Form Sidebar
|
|
97
|
+
|
|
98
|
+
Place fields in a right sidebar panel:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
.form(({ v, f }) =>
|
|
102
|
+
v.collectionForm({
|
|
103
|
+
sidebar: {
|
|
104
|
+
position: "right",
|
|
105
|
+
fields: [f.isActive, f.avatar, f.status],
|
|
106
|
+
},
|
|
107
|
+
fields: [ /* main content sections */ ],
|
|
108
|
+
}),
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Computed Fields
|
|
113
|
+
|
|
114
|
+
Auto-compute values from other fields:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
{
|
|
118
|
+
field: f.slug,
|
|
119
|
+
compute: {
|
|
120
|
+
handler: ({ data }) => {
|
|
121
|
+
if (data.name && !data.slug?.trim()) {
|
|
122
|
+
return slugify(data.name);
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
},
|
|
126
|
+
deps: ({ data }) => [data.name, data.slug],
|
|
127
|
+
debounce: 300,
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| Option | Type | Description |
|
|
133
|
+
| ---------- | ---------------- | ------------------------ |
|
|
134
|
+
| `handler` | `(ctx) => value` | Compute function |
|
|
135
|
+
| `deps` | `(ctx) => any[]` | Reactive dependencies |
|
|
136
|
+
| `debounce` | `number` | Debounce in milliseconds |
|
|
137
|
+
|
|
138
|
+
### Conditional Visibility
|
|
139
|
+
|
|
140
|
+
Show or hide fields based on other field values:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
{
|
|
144
|
+
field: f.cancellationReason,
|
|
145
|
+
hidden: ({ data }) => data.status !== "cancelled",
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Read-only fields:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
{
|
|
153
|
+
field: f.customerName,
|
|
154
|
+
readOnly: ({ data }) => !!data.customer,
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Section-level visibility:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
{
|
|
162
|
+
type: "section",
|
|
163
|
+
label: { en: "SEO" },
|
|
164
|
+
hidden: ({ data }) => !data.showSeo,
|
|
165
|
+
fields: [f.metaTitle, f.metaDescription],
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Dashboard
|
|
170
|
+
|
|
171
|
+
Configure in `config/admin.ts` under the `dashboard` key:
|
|
172
|
+
|
|
173
|
+
```ts title="config/admin.ts"
|
|
174
|
+
import { adminConfig } from "#questpie/factories";
|
|
175
|
+
|
|
176
|
+
export default adminConfig({
|
|
177
|
+
dashboard: {
|
|
178
|
+
title: { en: "Dashboard" },
|
|
179
|
+
description: { en: "Overview of your app" },
|
|
180
|
+
columns: 4,
|
|
181
|
+
actions: [
|
|
182
|
+
{
|
|
183
|
+
id: "new-post",
|
|
184
|
+
href: "/admin/collections/posts?create=true",
|
|
185
|
+
label: { en: "New Post" },
|
|
186
|
+
icon: { type: "icon", props: { name: "ph:plus" } },
|
|
187
|
+
variant: "primary",
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
sections: [
|
|
191
|
+
{ id: "today", label: { en: "Today" }, layout: "grid", columns: 4 },
|
|
192
|
+
{ id: "business", label: { en: "Business" }, layout: "grid", columns: 4 },
|
|
193
|
+
],
|
|
194
|
+
items: [
|
|
195
|
+
/* widget items — see widget types below */
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Widget Types
|
|
202
|
+
|
|
203
|
+
**Stats** — count records with optional filter:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
{
|
|
207
|
+
sectionId: "today",
|
|
208
|
+
id: "pending",
|
|
209
|
+
type: "stats",
|
|
210
|
+
collection: "appointments",
|
|
211
|
+
label: { en: "Pending" },
|
|
212
|
+
filter: { status: "pending" },
|
|
213
|
+
span: 1,
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Value** — custom-loaded value with trend:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
{
|
|
221
|
+
sectionId: "business",
|
|
222
|
+
id: "revenue",
|
|
223
|
+
type: "value",
|
|
224
|
+
span: 2,
|
|
225
|
+
refreshInterval: 1000 * 60 * 5,
|
|
226
|
+
loader: async ({ app }) => ({
|
|
227
|
+
value: 42000,
|
|
228
|
+
formatted: "42,000 EUR",
|
|
229
|
+
label: { en: "Monthly Revenue" },
|
|
230
|
+
trend: { value: "+12%" },
|
|
231
|
+
}),
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Progress** — progress bar toward a goal:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
{
|
|
239
|
+
sectionId: "business",
|
|
240
|
+
id: "goal",
|
|
241
|
+
type: "progress",
|
|
242
|
+
span: 1,
|
|
243
|
+
showPercentage: true,
|
|
244
|
+
label: { en: "Monthly Goal" },
|
|
245
|
+
loader: async ({ app }) => ({ current: 350, target: 500 }),
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Chart** — chart from field values:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
{
|
|
253
|
+
sectionId: "business",
|
|
254
|
+
id: "by-status",
|
|
255
|
+
type: "chart",
|
|
256
|
+
collection: "appointments",
|
|
257
|
+
field: "status",
|
|
258
|
+
chartType: "pie",
|
|
259
|
+
label: { en: "By Status" },
|
|
260
|
+
span: 1,
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Recent Items** — list recent records:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
{
|
|
268
|
+
sectionId: "ops",
|
|
269
|
+
id: "recent",
|
|
270
|
+
type: "recentItems",
|
|
271
|
+
collection: "appointments",
|
|
272
|
+
label: { en: "Recent" },
|
|
273
|
+
limit: 6,
|
|
274
|
+
dateField: "scheduledAt",
|
|
275
|
+
span: 2,
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Timeline** — activity stream:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
{
|
|
283
|
+
sectionId: "ops",
|
|
284
|
+
id: "activity",
|
|
285
|
+
type: "timeline",
|
|
286
|
+
label: { en: "Activity" },
|
|
287
|
+
maxItems: 8,
|
|
288
|
+
showTimestamps: true,
|
|
289
|
+
timestampFormat: "relative",
|
|
290
|
+
loader: async ({ app }) => {
|
|
291
|
+
const res = await app.collections.appointments.find({
|
|
292
|
+
limit: 8,
|
|
293
|
+
orderBy: { updatedAt: "desc" },
|
|
294
|
+
});
|
|
295
|
+
return res.docs.map((apt) => ({
|
|
296
|
+
id: apt.id,
|
|
297
|
+
title: apt.displayTitle,
|
|
298
|
+
description: `Status: ${apt.status}`,
|
|
299
|
+
timestamp: apt.updatedAt,
|
|
300
|
+
variant: apt.status === "completed" ? "success" : "warning",
|
|
301
|
+
href: `/admin/collections/appointments/${apt.id}`,
|
|
302
|
+
}));
|
|
303
|
+
},
|
|
304
|
+
span: 2,
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Sidebar
|
|
309
|
+
|
|
310
|
+
Configure in `config/admin.ts` under the `sidebar` key:
|
|
311
|
+
|
|
312
|
+
```ts title="config/admin.ts"
|
|
313
|
+
import { adminConfig } from "#questpie/factories";
|
|
314
|
+
|
|
315
|
+
export default adminConfig({
|
|
316
|
+
sidebar: {
|
|
317
|
+
sections: [
|
|
318
|
+
{ id: "overview", title: { en: "Overview" } },
|
|
319
|
+
{ id: "content", title: { en: "Content" } },
|
|
320
|
+
{ id: "external", title: { en: "External" } },
|
|
321
|
+
],
|
|
322
|
+
items: [
|
|
323
|
+
{
|
|
324
|
+
sectionId: "overview",
|
|
325
|
+
type: "link",
|
|
326
|
+
label: { en: "Dashboard" },
|
|
327
|
+
href: "/admin",
|
|
328
|
+
icon: { type: "icon", props: { name: "ph:house" } },
|
|
329
|
+
},
|
|
330
|
+
{ sectionId: "overview", type: "global", global: "siteSettings" },
|
|
331
|
+
{ sectionId: "content", type: "collection", collection: "posts" },
|
|
332
|
+
{
|
|
333
|
+
sectionId: "external",
|
|
334
|
+
type: "link",
|
|
335
|
+
label: { en: "Open Website" },
|
|
336
|
+
href: "/",
|
|
337
|
+
external: true,
|
|
338
|
+
icon: { type: "icon", props: { name: "ph:arrow-square-out" } },
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Items appear in definition order within their section.
|
|
346
|
+
|
|
347
|
+
Modules contribute sidebar items automatically. `adminModule` adds "Administration" with user management. `auditModule` adds an audit log item.
|
|
348
|
+
|
|
349
|
+
## Filters & Saved Views
|
|
350
|
+
|
|
351
|
+
Filters are auto-generated from field definitions:
|
|
352
|
+
|
|
353
|
+
| Field Type | Filter Operators |
|
|
354
|
+
| ------------------- | ---------------------------------------- |
|
|
355
|
+
| `text` | Contains, equals, starts with, ends with |
|
|
356
|
+
| `number` | Equals, greater than, less than, between |
|
|
357
|
+
| `boolean` | Is true, is false |
|
|
358
|
+
| `select` | Is, is not, in |
|
|
359
|
+
| `date` / `datetime` | Before, after, between |
|
|
360
|
+
| `relation` | Is (picker) |
|
|
361
|
+
|
|
362
|
+
Users can save filter + sort + column combinations as named views.
|
|
363
|
+
|
|
364
|
+
## Bulk Actions
|
|
365
|
+
|
|
366
|
+
List views support multi-select. Check rows, then use the floating toolbar. Built-in: **Delete** (with confirmation). Soft-delete collections soft-delete instead of permanent removal.
|
|
367
|
+
|
|
368
|
+
## History & Versions
|
|
369
|
+
|
|
370
|
+
Click the clock icon in the form toolbar. Two tabs:
|
|
371
|
+
|
|
372
|
+
| Tab | Shows | Requires |
|
|
373
|
+
| ------------ | ---------------------------------------------- | ----------------------------- |
|
|
374
|
+
| **Activity** | Audit log (create, update, delete, transition) | `auditModule` |
|
|
375
|
+
| **Versions** | Full document snapshots with restore | `.versioning()` on collection |
|
|
376
|
+
|
|
377
|
+
Enable versioning:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
export const pages = collection("pages")
|
|
381
|
+
.fields(({ f }) => ({ ... }))
|
|
382
|
+
.options({ versioning: true });
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Disable audit for a specific collection:
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
export const logs = collection("logs")
|
|
389
|
+
.admin(() => ({ audit: false }))
|
|
390
|
+
.fields(({ f }) => ({ ... }));
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Common Mistakes
|
|
394
|
+
|
|
395
|
+
1. **HIGH: Defining columns that don't match field names** — `columns: [f.name]` requires a `name` field in the collection's `.fields()`. Mismatches cause empty columns.
|
|
396
|
+
|
|
397
|
+
2. **MEDIUM: Not specifying `searchableFields`** — table search bar won't work unless you explicitly list which fields to search.
|
|
398
|
+
|
|
399
|
+
3. **MEDIUM: Forgetting sidebar section ordering** — items appear in definition order. If you want "Dashboard" at the top, define it first in the `items` array.
|
|
400
|
+
|
|
401
|
+
4. **MEDIUM: Missing `sectionId` on sidebar items** — every item must reference an existing section ID.
|
|
402
|
+
|
|
403
|
+
5. **LOW: Not setting `defaultSort`** — records appear in database insertion order which is usually not what users expect.
|
|
404
|
+
|
|
405
|
+
## Form Views and Live Preview
|
|
406
|
+
|
|
407
|
+
Form views connect to the existing Live Preview system when the collection has `.preview()` configured. Keep `v.collectionForm()` as the form surface; do not introduce a separate visual-edit form API, a second default form view, or parallel preview API names. The form editor remains the source of patches, refreshes, commits, and resyncs.
|
|
408
|
+
|
|
409
|
+
### Enabling Preview on a Collection
|
|
410
|
+
|
|
411
|
+
Add `.preview()` to the collection definition:
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
export const pages = collection("pages")
|
|
415
|
+
.fields(({ f }) => ({
|
|
416
|
+
title: f.text().required().localized(),
|
|
417
|
+
slug: f.text().required(),
|
|
418
|
+
content: f.blocks().localized(),
|
|
419
|
+
}))
|
|
420
|
+
.preview({
|
|
421
|
+
enabled: true,
|
|
422
|
+
position: "right",
|
|
423
|
+
defaultWidth: 50,
|
|
424
|
+
url: ({ record }) => `/${record.slug}?preview=true`,
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### How It Works
|
|
429
|
+
|
|
430
|
+
1. The form view detects `.preview()` config and opens a split-screen layout
|
|
431
|
+
2. The preview iframe mirrors form state with snapshot, patch, refresh, commit, and resync messages
|
|
432
|
+
3. Save/autosave/Cmd+S/history/workflow/locks/actions stay in the form lifecycle
|
|
433
|
+
4. The preview page uses `useCollectionPreview({ initialData, onRefresh })`
|
|
434
|
+
5. `PreviewProvider`, `PreviewField`, and `BlockRenderer` wire field and block annotations
|
|
435
|
+
|
|
436
|
+
### Frontend Preparation Checklist
|
|
437
|
+
|
|
438
|
+
Use this checklist before expecting visual editing to work:
|
|
439
|
+
|
|
440
|
+
1. The collection has `.preview({ url })`.
|
|
441
|
+
2. The page loader returns the complete rendered record shape.
|
|
442
|
+
3. Public workflow reads use `stage: "published"`; if public client/HTTP access is enabled, anonymous read access also requires `input?.stage === "published"`. Preview/draft-mode reads load the working record for authorized editors.
|
|
443
|
+
4. The page renderer calls `useCollectionPreview({ initialData, onRefresh })`.
|
|
444
|
+
5. The rendered page is wrapped in `PreviewProvider preview={preview}`.
|
|
445
|
+
6. UI reads from `preview.data`, not directly from loader data.
|
|
446
|
+
7. Scalar text uses `PreviewField field="..." editable="text" | "textarea"` when inline editing is expected.
|
|
447
|
+
8. Blocks render through `BlockRenderer` with `selectedBlockId` and `onBlockClick`.
|
|
448
|
+
9. `BlockScopeProvider` is only needed for custom/manual block rendering outside `BlockRenderer`.
|
|
449
|
+
10. Add/remove/reorder/nesting block operations stay in the existing block editor.
|
|
@@ -116,10 +116,10 @@ src/
|
|
|
116
116
|
- **`src/questpie/server/modules.ts`** — Module dependencies: `export default [adminModule, openApiModule] as const`.
|
|
117
117
|
- **`src/questpie/server/config/auth.ts`** — Auth config via `authConfig()` factory.
|
|
118
118
|
- **`src/questpie/server/config/admin.ts`** — Admin config (sidebar, dashboard, branding, locale) via `adminConfig()` factory.
|
|
119
|
-
- **`src/questpie/server/config/app.ts`** —
|
|
119
|
+
- **`src/questpie/server/config/app.ts`** — _(optional, not scaffolded)_ App config (locale, access, hooks, context) via `appConfig()`. Create when needed.
|
|
120
120
|
- **`src/questpie/server/config/openapi.ts`** — OpenAPI config via `openApiConfig()` factory.
|
|
121
|
-
- **`src/questpie/server/.generated/index.ts`** — Codegen output. Exports typed `app` instance and `App` type. Run `
|
|
122
|
-
- **`src/questpie/admin/.generated/client.ts`** — Codegen output: pre-built admin client config. Run `
|
|
121
|
+
- **`src/questpie/server/.generated/index.ts`** — Codegen output. Exports typed `app` instance and `App` type. Run `bun run questpie:generate` to regenerate.
|
|
122
|
+
- **`src/questpie/admin/.generated/client.ts`** — Codegen output: pre-built admin client config. Run `bun run questpie:generate` to regenerate.
|
|
123
123
|
- **`src/lib/env.ts`** — Type-safe env variables via `@t3-oss/env-core`. Add new env vars here with Zod schemas.
|
|
124
124
|
- **`questpie.config.ts`** — CLI config (migration directory, app reference).
|
|
125
125
|
- **`src/routes/api/$.ts`** — API catch-all handler. Serves REST + OpenAPI docs at `/api/docs`.
|
|
@@ -194,12 +194,12 @@ Then (preferred):
|
|
|
194
194
|
|
|
195
195
|
1. Use `bun questpie add collection <name>` to scaffold files
|
|
196
196
|
2. Codegen runs automatically
|
|
197
|
-
3. Run `bun
|
|
197
|
+
3. Run `bun run migrate:create` to generate migration
|
|
198
198
|
|
|
199
199
|
Manual workflow (if you create files yourself):
|
|
200
200
|
|
|
201
|
-
1. Run `
|
|
202
|
-
2. Run `bun
|
|
201
|
+
1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
|
|
202
|
+
2. Run `bun run migrate:create` to generate migration
|
|
203
203
|
|
|
204
204
|
Collections are auto-discovered by codegen — no manual registration needed.
|
|
205
205
|
|
|
@@ -233,12 +233,12 @@ Then (preferred):
|
|
|
233
233
|
|
|
234
234
|
1. Use `bun questpie add global <name>` to scaffold files
|
|
235
235
|
2. Codegen runs automatically
|
|
236
|
-
3. Run `bun
|
|
236
|
+
3. Run `bun run migrate:create`
|
|
237
237
|
|
|
238
238
|
Manual workflow (if you create files yourself):
|
|
239
239
|
|
|
240
|
-
1. Run `
|
|
241
|
-
2. Run `bun
|
|
240
|
+
1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
|
|
241
|
+
2. Run `bun run migrate:create`
|
|
242
242
|
|
|
243
243
|
Globals are auto-discovered by codegen — no manual registration needed.
|
|
244
244
|
|
|
@@ -270,7 +270,7 @@ export default route()
|
|
|
270
270
|
**Step 2 — Run codegen:**
|
|
271
271
|
|
|
272
272
|
```bash
|
|
273
|
-
|
|
273
|
+
bun run questpie:generate
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
The route is auto-discovered and available at `/api/get-stats`.
|
|
@@ -429,7 +429,7 @@ fields: ({ f }) => ({
|
|
|
429
429
|
### Admin Configuration (Client-Side)
|
|
430
430
|
|
|
431
431
|
The admin client config is auto-generated by codegen into `admin/.generated/client.ts`.
|
|
432
|
-
No manual builder setup is needed. Run `
|
|
432
|
+
No manual builder setup is needed. Run `bun run questpie:generate` to regenerate.
|
|
433
433
|
|
|
434
434
|
```ts
|
|
435
435
|
// src/questpie/admin/admin.ts (re-export for convenience)
|
|
@@ -498,8 +498,12 @@ Optional (with defaults):
|
|
|
498
498
|
bun dev # Start dev server
|
|
499
499
|
bun build # Build for production
|
|
500
500
|
bun start # Start production server
|
|
501
|
-
bun
|
|
502
|
-
bun
|
|
501
|
+
bun run migrate # Run database migrations
|
|
502
|
+
bun run migrate:create # Create new migration
|
|
503
|
+
bun run routes:generate # Regenerate TanStack Router route tree
|
|
504
|
+
bun run questpie:generate # Regenerate codegen output
|
|
505
|
+
bun run scaffold:generate # Regenerate route tree and QUESTPIE output
|
|
506
|
+
bun run scaffold:verify # Regenerate codegen and type-check
|
|
503
507
|
docker compose up -d # Start PostgreSQL
|
|
504
508
|
```
|
|
505
509
|
|
|
@@ -11,9 +11,12 @@ This is a [QUESTPIE](https://questpie.com) project scaffolded with `create-quest
|
|
|
11
11
|
| `bun start` | Start production server |
|
|
12
12
|
| `bun questpie add <type> <name>` | Scaffold a new entity (collection, seed, etc.) |
|
|
13
13
|
| `bun questpie add --list` | List all available scaffold types |
|
|
14
|
-
| `bun
|
|
15
|
-
| `bun questpie
|
|
16
|
-
| `bun
|
|
14
|
+
| `bun run routes:generate` | Regenerate TanStack Router route tree |
|
|
15
|
+
| `bun run questpie:generate` | Regenerate .generated/index.ts |
|
|
16
|
+
| `bun run scaffold:generate` | Regenerate route tree and QUESTPIE output |
|
|
17
|
+
| `bun run scaffold:verify` | Regenerate codegen and type-check |
|
|
18
|
+
| `bun run migrate:create` | Generate a migration from schema diff |
|
|
19
|
+
| `bun run migrate` | Run pending migrations |
|
|
17
20
|
| `bun questpie seed` | Run pending seeds |
|
|
18
21
|
| `docker compose up -d` | Start PostgreSQL |
|
|
19
22
|
|
|
@@ -53,8 +56,8 @@ src/questpie/
|
|
|
53
56
|
- **`src/questpie/server/modules.ts`** — Module dependencies: `export default [adminModule, openApiModule] as const`.
|
|
54
57
|
- **`src/questpie/server/config/auth.ts`** — Auth config via `authConfig()` factory.
|
|
55
58
|
- **`src/questpie/server/config/admin.ts`** — Admin config (sidebar, dashboard, branding, locale) via `adminConfig()` factory.
|
|
56
|
-
- **`src/questpie/server/config/app.ts`** —
|
|
57
|
-
- **`src/questpie/server/.generated/index.ts`** — Codegen output. Exports typed `app` instance and `App` type. Run `
|
|
59
|
+
- **`src/questpie/server/config/app.ts`** — _(optional, not scaffolded)_ App config (locale, access, hooks, context) via `appConfig()`. Create when needed.
|
|
60
|
+
- **`src/questpie/server/.generated/index.ts`** — Codegen output. Exports typed `app` instance and `App` type. Run `bun run questpie:generate` to regenerate.
|
|
58
61
|
- **`src/lib/env.ts`** — Type-safe env variables via `@t3-oss/env-core`. Add new env vars here with Zod schemas.
|
|
59
62
|
- **`questpie.config.ts`** — CLI config (migration directory, app reference).
|
|
60
63
|
- **`src/routes/api/$.ts`** — API catch-all handler. Serves REST + OpenAPI docs at `/api/docs`.
|
|
@@ -81,7 +84,7 @@ Preferred workflow:
|
|
|
81
84
|
|
|
82
85
|
1. Run `bun questpie add collection my-thing`
|
|
83
86
|
2. The CLI creates the file and auto-runs codegen
|
|
84
|
-
3. Run `bun
|
|
87
|
+
3. Run `bun run migrate:create`
|
|
85
88
|
|
|
86
89
|
Manual workflow:
|
|
87
90
|
|
|
@@ -90,8 +93,8 @@ Manual workflow:
|
|
|
90
93
|
import { collection } from "#questpie/factories";
|
|
91
94
|
export const myThing = collection("my-thing").fields(({ f }) => ({ ... }));
|
|
92
95
|
```
|
|
93
|
-
2. Run `
|
|
94
|
-
3. Run `bun
|
|
96
|
+
2. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
|
|
97
|
+
3. Run `bun run migrate:create` to generate migration
|
|
95
98
|
|
|
96
99
|
Collections are auto-discovered by codegen — no manual registration needed.
|
|
97
100
|
|
|
@@ -101,13 +104,13 @@ Preferred workflow:
|
|
|
101
104
|
|
|
102
105
|
1. Run `bun questpie add global my-global`
|
|
103
106
|
2. The CLI creates the file and auto-runs codegen
|
|
104
|
-
3. Run `bun
|
|
107
|
+
3. Run `bun run migrate:create`
|
|
105
108
|
|
|
106
109
|
Manual workflow:
|
|
107
110
|
|
|
108
111
|
1. Create `src/questpie/server/globals/my-global.ts` with a named export
|
|
109
|
-
2. Run `
|
|
110
|
-
3. Run `bun
|
|
112
|
+
2. Run `bun run questpie:generate`
|
|
113
|
+
3. Run `bun run migrate:create`
|
|
111
114
|
|
|
112
115
|
### Add a server route (end-to-end type-safe)
|
|
113
116
|
|
|
@@ -126,7 +129,7 @@ Manual workflow:
|
|
|
126
129
|
});
|
|
127
130
|
```
|
|
128
131
|
|
|
129
|
-
2. Run `
|
|
132
|
+
2. Run `bun run questpie:generate` — route is auto-discovered and available at `/api/my-function`
|
|
130
133
|
|
|
131
134
|
See AGENTS.md for detailed route patterns, access control, and TanStack Query integration.
|
|
132
135
|
|
|
@@ -15,11 +15,14 @@ A [QUESTPIE](https://questpie.com) app built with TanStack Start.
|
|
|
15
15
|
# 1) Start PostgreSQL
|
|
16
16
|
docker compose up -d
|
|
17
17
|
|
|
18
|
-
# 2)
|
|
19
|
-
bun
|
|
18
|
+
# 2) Regenerate codegen and type-check
|
|
19
|
+
bun run scaffold:verify
|
|
20
20
|
|
|
21
|
-
# 3)
|
|
22
|
-
bun
|
|
21
|
+
# 3) Run migrations
|
|
22
|
+
bun run migrate
|
|
23
|
+
|
|
24
|
+
# 4) Start development server
|
|
25
|
+
bun run dev
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
- Admin panel: `http://localhost:3000/admin`
|
|
@@ -67,10 +70,13 @@ migrations/
|
|
|
67
70
|
| `bun build` | Build for production |
|
|
68
71
|
| `bun start` | Start production server |
|
|
69
72
|
| `bun check-types` | Type check |
|
|
73
|
+
| `bun run scaffold:generate` | Regenerate routes and QUESTPIE codegen |
|
|
74
|
+
| `bun run scaffold:verify` | Regenerate codegen and type-check |
|
|
75
|
+
| `bun run routes:generate` | Regenerate TanStack Router route tree |
|
|
76
|
+
| `bun run questpie:generate` | Regenerate `src/questpie/server/.generated/*` |
|
|
70
77
|
| `bun questpie add <type> <name>` | Scaffold entity files (auto-runs codegen) |
|
|
71
|
-
| `bun
|
|
72
|
-
| `bun
|
|
73
|
-
| `bunx questpie generate` | Regenerate `src/questpie/server/.generated/*` |
|
|
78
|
+
| `bun run migrate` | Run migrations |
|
|
79
|
+
| `bun run migrate:create` | Create migration |
|
|
74
80
|
|
|
75
81
|
## Adding a Collection
|
|
76
82
|
|
|
@@ -78,14 +84,14 @@ Preferred workflow:
|
|
|
78
84
|
|
|
79
85
|
1. Run `bun questpie add collection products`.
|
|
80
86
|
2. The CLI creates the file and runs codegen automatically.
|
|
81
|
-
3. Run `bun
|
|
87
|
+
3. Run `bun run migrate:create`.
|
|
82
88
|
|
|
83
89
|
Manual workflow (when you create files by hand):
|
|
84
90
|
|
|
85
91
|
1. Create a file in `src/questpie/server/collections/`.
|
|
86
92
|
2. Export a collection builder from that file.
|
|
87
|
-
3. Run `
|
|
88
|
-
4. Run `bun
|
|
93
|
+
3. Run `bun run questpie:generate`.
|
|
94
|
+
4. Run `bun run migrate:create`.
|
|
89
95
|
|
|
90
96
|
Collections are discovered automatically by codegen. No manual `app.ts` registration is required.
|
|
91
97
|
|
|
@@ -95,13 +101,13 @@ Preferred workflow:
|
|
|
95
101
|
|
|
96
102
|
1. Run `bun questpie add global marketing`.
|
|
97
103
|
2. The CLI creates the file and runs codegen automatically.
|
|
98
|
-
3. Run `bun
|
|
104
|
+
3. Run `bun run migrate:create`.
|
|
99
105
|
|
|
100
106
|
Manual workflow (when you create files by hand):
|
|
101
107
|
|
|
102
108
|
1. Create a file in `src/questpie/server/globals/`.
|
|
103
109
|
2. Export a global builder from that file.
|
|
104
|
-
3. Run `
|
|
105
|
-
4. Run `bun
|
|
110
|
+
3. Run `bun run questpie:generate`.
|
|
111
|
+
4. Run `bun run migrate:create`.
|
|
106
112
|
|
|
107
113
|
Globals are discovered automatically by codegen. No manual `app.ts` registration is required.
|