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.
Files changed (40) hide show
  1. package/README.md +10 -6
  2. package/dist/index.mjs +139 -24
  3. package/package.json +5 -3
  4. package/skills/questpie/AGENTS.md +2670 -0
  5. package/skills/questpie/SKILL.md +260 -0
  6. package/skills/questpie/references/auth.md +121 -0
  7. package/skills/questpie/references/business-logic.md +550 -0
  8. package/skills/questpie/references/codegen-plugin-api.md +382 -0
  9. package/skills/questpie/references/crud-api.md +378 -0
  10. package/skills/questpie/references/data-modeling.md +493 -0
  11. package/skills/questpie/references/extend.md +557 -0
  12. package/skills/questpie/references/field-types.md +386 -0
  13. package/skills/questpie/references/infrastructure-adapters.md +545 -0
  14. package/skills/questpie/references/multi-tenancy.md +364 -0
  15. package/skills/questpie/references/production.md +475 -0
  16. package/skills/questpie/references/query-operators.md +125 -0
  17. package/skills/questpie/references/quickstart.md +564 -0
  18. package/skills/questpie/references/rules.md +389 -0
  19. package/skills/questpie/references/tanstack-query.md +520 -0
  20. package/skills/questpie-admin/AGENTS.md +1508 -0
  21. package/skills/questpie-admin/SKILL.md +436 -0
  22. package/skills/questpie-admin/references/blocks.md +331 -0
  23. package/skills/questpie-admin/references/custom-ui.md +305 -0
  24. package/skills/questpie-admin/references/views.md +449 -0
  25. package/templates/tanstack-start/AGENTS.md +17 -13
  26. package/templates/tanstack-start/CLAUDE.md +15 -12
  27. package/templates/tanstack-start/README.md +19 -13
  28. package/templates/tanstack-start/env.example +1 -1
  29. package/templates/tanstack-start/package.json +20 -6
  30. package/templates/tanstack-start/src/lib/env.ts +1 -1
  31. package/templates/tanstack-start/src/lib/query-client.ts +10 -1
  32. package/templates/tanstack-start/src/questpie/server/config/admin.ts +27 -30
  33. package/templates/tanstack-start/src/routeTree.gen.ts +138 -0
  34. package/templates/tanstack-start/src/routes/__root.tsx +0 -2
  35. package/templates/tanstack-start/src/routes/admin/$.tsx +12 -1
  36. package/templates/tanstack-start/src/routes/admin/index.tsx +12 -5
  37. package/templates/tanstack-start/src/routes/admin.tsx +8 -1
  38. package/templates/tanstack-start/src/tanstack-start.d.ts +1 -0
  39. package/templates/tanstack-start/src/vite-env.d.ts +1 -0
  40. 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`** — *(optional, not scaffolded)* App config (locale, access, hooks, context) via `appConfig()`. Create when needed.
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 `bunx questpie generate` to regenerate.
122
- - **`src/questpie/admin/.generated/client.ts`** — Codegen output: pre-built admin client config. Run `bunx questpie generate` to regenerate.
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 questpie migrate:create` to generate migration
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 `bunx questpie generate` to regenerate `.generated/index.ts`
202
- 2. Run `bun questpie migrate:create` to generate migration
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 questpie migrate:create`
236
+ 3. Run `bun run migrate:create`
237
237
 
238
238
  Manual workflow (if you create files yourself):
239
239
 
240
- 1. Run `bunx questpie generate` to regenerate `.generated/index.ts`
241
- 2. Run `bun questpie migrate:create`
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
- bunx questpie generate
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 `bunx questpie generate` to regenerate.
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 questpie migrate # Run database migrations
502
- bun questpie migrate:create # Create new migration
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 questpie generate` | Regenerate .generated/index.ts |
15
- | `bun questpie migrate:create` | Generate a migration from schema diff |
16
- | `bun questpie migrate` | Run pending migrations |
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`** — *(optional, not scaffolded)* App config (locale, access, hooks, context) via `appConfig()`. Create when needed.
57
- - **`src/questpie/server/.generated/index.ts`** — Codegen output. Exports typed `app` instance and `App` type. Run `bunx questpie generate` to regenerate.
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 questpie migrate:create`
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 `bunx questpie generate` to regenerate `.generated/index.ts`
94
- 3. Run `bun questpie migrate:create` to generate migration
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 questpie migrate:create`
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 `bunx questpie generate`
110
- 3. Run `bun questpie migrate:create`
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 `bunx questpie generate` — route is auto-discovered and available at `/api/my-function`
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) Run migrations
19
- bun questpie migrate
18
+ # 2) Regenerate codegen and type-check
19
+ bun run scaffold:verify
20
20
 
21
- # 3) Start development server
22
- bun dev
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 questpie migrate` | Run migrations |
72
- | `bun questpie migrate:create` | Create migration |
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 questpie migrate:create`.
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 `bunx questpie generate`.
88
- 4. Run `bun questpie migrate:create`.
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 questpie migrate:create`.
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 `bunx questpie generate`.
105
- 4. Run `bun questpie migrate:create`.
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.
@@ -6,7 +6,7 @@ APP_URL=http://localhost:3000
6
6
  PORT=3000
7
7
 
8
8
  # Auth (Better Auth)
9
- BETTER_AUTH_SECRET=your-secret-key-change-in-production
9
+ BETTER_AUTH_SECRET={{authSecret}}
10
10
 
11
11
  # Email Adapter (console | smtp)
12
12
  MAIL_ADAPTER=console