create-questpie 2.0.3 → 2.0.4

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 (35) hide show
  1. package/dist/index.mjs +244 -30
  2. package/package.json +1 -1
  3. package/skills/questpie/AGENTS.md +299 -98
  4. package/skills/questpie/SKILL.md +50 -17
  5. package/skills/questpie/coverage.json +213 -0
  6. package/skills/questpie/references/auth.md +119 -4
  7. package/skills/questpie/references/business-logic.md +126 -56
  8. package/skills/questpie/references/crud-api.md +231 -29
  9. package/skills/questpie/references/data-modeling.md +22 -6
  10. package/skills/questpie/references/extend.md +34 -7
  11. package/skills/questpie/references/field-types.md +14 -2
  12. package/skills/questpie/references/infrastructure-adapters.md +207 -32
  13. package/skills/questpie/references/mcp.md +147 -0
  14. package/skills/questpie/references/multi-tenancy.md +1 -2
  15. package/skills/questpie/references/production.md +218 -53
  16. package/skills/questpie/references/quickstart.md +6 -8
  17. package/skills/questpie/references/rules.md +86 -21
  18. package/skills/questpie/references/sandbox.md +110 -0
  19. package/skills/questpie/references/tanstack-query.md +34 -11
  20. package/skills/questpie/references/type-inference.md +167 -0
  21. package/skills/questpie/references/workflows.md +155 -0
  22. package/skills/questpie-admin/AGENTS.md +47 -40
  23. package/skills/questpie-admin/SKILL.md +46 -39
  24. package/skills/questpie-admin/references/custom-ui.md +1 -1
  25. package/templates/tanstack-start/AGENTS.md +15 -8
  26. package/templates/tanstack-start/CLAUDE.md +12 -5
  27. package/templates/tanstack-start/README.md +7 -6
  28. package/templates/tanstack-start/package.json +1 -0
  29. package/templates/tanstack-start/src/questpie/admin/modules.ts +3 -1
  30. package/templates/tanstack-start/src/questpie/server/.generated/factories.ts +10 -9
  31. package/templates/tanstack-start/src/questpie/server/config/auth.ts +1 -1
  32. package/templates/tanstack-start/src/questpie/server/modules.ts +4 -5
  33. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +2 -1
  34. package/templates/tanstack-start/src/routes/api/$.ts +1 -2
  35. package/templates/tanstack-start/vite.config.ts +2 -2
@@ -0,0 +1,155 @@
1
+ ---
2
+ name: questpie-core/workflows
3
+ description:
4
+ QUESTPIE durable workflows long-running business processes replay steps sleep waitForEvent invoke compensation cron admin UI workflow service
5
+ - questpie-core
6
+ ---
7
+
8
+ # Durable Workflows
9
+
10
+ Use `@questpie/workflows` when business logic spans multiple steps, waits on time or external events, needs retry-safe side effects, or should survive process restarts.
11
+
12
+ ## Install And Register
13
+
14
+ ```bash
15
+ bun add @questpie/workflows
16
+ ```
17
+
18
+ ```ts title="modules.ts"
19
+ import { workflowsModule } from "@questpie/workflows/modules/workflows";
20
+ export default [workflowsModule] as const;
21
+ ```
22
+
23
+ `workflowsModule` carries its codegen plugin. Do not also add `workflowsPlugin()` to `questpie.config.ts` unless you are doing a custom module setup that deliberately omits `workflowsModule`.
24
+
25
+ Runtime options (route access rule — default admin-only — and execution-lease settings) go in plugin-discovered `config/workflows.ts` using the `workflowsConfig()` factory from `@questpie/workflows/server`.
26
+
27
+ For admin UI pages/widgets, register the client module:
28
+
29
+ ```ts title="questpie/admin/modules.ts"
30
+ import adminClientModule from "@questpie/admin/client-module";
31
+ import { workflowsClientModule } from "@questpie/workflows/client/modules/workflows";
32
+ export default {
33
+ name: "app-admin" as const,
34
+ views: { ...adminClientModule.views, ...workflowsClientModule.views },
35
+ components: {
36
+ ...adminClientModule.components,
37
+ ...workflowsClientModule.components,
38
+ },
39
+ fields: { ...adminClientModule.fields, ...workflowsClientModule.fields },
40
+ pages: { ...adminClientModule.pages, ...workflowsClientModule.pages },
41
+ widgets: { ...adminClientModule.widgets, ...workflowsClientModule.widgets },
42
+ blocks: { ...adminClientModule.blocks, ...workflowsClientModule.blocks },
43
+ };
44
+ ```
45
+
46
+ ## Define A Workflow
47
+
48
+ Put workflow definitions in `workflows/*.ts`:
49
+
50
+ ```ts title="workflows/production-order.ts"
51
+ import { workflow } from "@questpie/workflows";
52
+ import { z } from "zod";
53
+
54
+ export default workflow({
55
+ name: "production-order",
56
+ schema: z.object({
57
+ orderId: z.string(),
58
+ }),
59
+ timeout: "7d",
60
+ handler: async ({ input, step, ctx, log }) => {
61
+ const order = await step.run("load-order", async () => {
62
+ return ctx.collections.productionOrders.findOne({
63
+ where: { id: input.orderId },
64
+ with: { toy: true },
65
+ });
66
+ });
67
+ if (!order) throw new Error("Production order not found");
68
+
69
+ await step.run("reserve-materials", async () => {
70
+ await ctx.queue.recalculateMaterialPlan.publish({
71
+ orderId: input.orderId,
72
+ });
73
+ });
74
+
75
+ await step.waitForEvent("materials-ready", {
76
+ event: "materials.available",
77
+ match: { orderId: input.orderId },
78
+ timeout: "2d",
79
+ });
80
+
81
+ await step.run("notify-scheduled", async () => {
82
+ await ctx.email.sendTemplate({
83
+ template: "productionScheduled",
84
+ input: { orderId: input.orderId },
85
+ to: order.ownerEmail,
86
+ });
87
+ });
88
+
89
+ log.info("Production order workflow completed");
90
+ return { status: "scheduled" };
91
+ },
92
+ });
93
+ ```
94
+
95
+ Run codegen after adding workflow files:
96
+
97
+ ```bash
98
+ bun questpie generate
99
+ ```
100
+
101
+ ## Trigger And Signal
102
+
103
+ Use injected `workflows` from route, job, hook, or service context:
104
+
105
+ ```ts title="routes/start-production.ts"
106
+ import { route } from "questpie/services";
107
+ import { z } from "zod";
108
+
109
+ export default route()
110
+ .post()
111
+ .schema(z.object({ orderId: z.string() }))
112
+ .handler(async ({ input, workflows }) => {
113
+ const result = await workflows.trigger("production-order", {
114
+ orderId: input.orderId,
115
+ });
116
+ return { instanceId: result.instanceId };
117
+ });
118
+ ```
119
+
120
+ Signal waiting workflows:
121
+
122
+ ```ts
123
+ await workflows.sendEvent(
124
+ "materials.available",
125
+ { receivedAt: new Date().toISOString() },
126
+ { orderId },
127
+ );
128
+ ```
129
+
130
+ ## Cron Workflows
131
+
132
+ Use workflow-level `cron` for recurring long-running processes:
133
+
134
+ ```ts
135
+ export default workflow({
136
+ name: "nightly-material-plan",
137
+ schema: z.object({}),
138
+ cron: { schedule: "0 2 * * *", overlap: "skip" },
139
+ handler: async ({ step, ctx }) => {
140
+ await step.run("recalculate", async () => {
141
+ await ctx.queue.recalculateMaterialPlan.publish({});
142
+ });
143
+ },
144
+ });
145
+ ```
146
+
147
+ On Node/Bun workers, `app.queue.listen()` runs workflow jobs and maintenance. On Cloudflare Workers, use `cloudflareQueuesAdapter`, export `createCloudflareWorkerHandlers(app)`, and configure a Cron Trigger for workflow maintenance.
148
+
149
+ ## Rules
150
+
151
+ - Keep external side effects inside `step.run()` so replay does not repeat them.
152
+ - Use stable step names. Renaming a step changes replay identity.
153
+ - Use idempotency keys when calling external APIs.
154
+ - Use `step.waitForEvent()` for durable waits instead of polling loops.
155
+ - Keep workflow definitions in `workflows/`; do not define them inside route/job files.
@@ -20,7 +20,8 @@ For the complete admin reference with all topics expanded: `AGENTS.md`
20
20
  - **@base-ui/react** primitives (NOT @radix-ui)
21
21
  - **@iconify/react** with Phosphor icon set (`ph:icon-name`)
22
22
  - **sonner** for toasts — `toast.error()`, `toast.success()`
23
- - Brutalist flat design: `--radius: 0px`, no shadows
23
+ - QUESTPIE Neutral Design: flat surfaces, soft neutral geometry,
24
+ tokenized radius, and restrained floating shadows
24
25
 
25
26
  ## Setup
26
27
 
@@ -33,8 +34,7 @@ bun add @questpie/admin
33
34
  ### 2. Runtime Config
34
35
 
35
36
  ```ts title="questpie.config.ts"
36
- import { runtimeConfig } from "questpie";
37
-
37
+ import { runtimeConfig } from "questpie/app";
38
38
  export default runtimeConfig({
39
39
  app: { url: process.env.APP_URL || "http://localhost:3000" },
40
40
  db: { url: process.env.DATABASE_URL },
@@ -47,7 +47,8 @@ The admin module contributes the codegen plugin automatically. It discovers `con
47
47
  ### 3. Modules
48
48
 
49
49
  ```ts title="modules.ts"
50
- import { adminModule, auditModule } from "@questpie/admin/server";
50
+ import { adminModule } from "@questpie/admin/modules/admin";
51
+ import { auditModule } from "@questpie/admin/modules/audit";
51
52
 
52
53
  export default [adminModule, auditModule] as const;
53
54
  ```
@@ -57,6 +58,26 @@ export default [adminModule, auditModule] as const;
57
58
  | `adminModule` | User collection, auth pages, admin UI |
58
59
  | `auditModule` | Audit log collection, timeline widget |
59
60
 
61
+ ### Auth/User Contract - Critical
62
+
63
+ `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"`.
64
+
65
+ 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:
66
+
67
+ ```ts title="collections/user.ts"
68
+ import { starterModule } from "questpie/app";
69
+ import { collection } from "#questpie/factories";
70
+
71
+ export default collection("user")
72
+ .merge(starterModule.collections.user)
73
+ .fields(({ f }) => ({
74
+ // add app-specific user fields here
75
+ internalNotes: f.textarea(),
76
+ }));
77
+ ```
78
+
79
+ 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.
80
+
60
81
  ### 4. Admin Config
61
82
 
62
83
  ```ts title="config/admin.ts"
@@ -129,44 +150,31 @@ export default adminConfig({
129
150
 
130
151
  The admin uses CSS variables for all theming. Override them in your own CSS file.
131
152
 
132
- ### Light Theme (`:root`)
133
-
134
- | Variable | Default | Purpose |
135
- | ---------------------- | --------- | -------------------------------- |
136
- | `--background` | `#FFFFFF` | Page background |
137
- | `--foreground` | `#0A0A0A` | Primary text |
138
- | `--card` | `#F8F8F8` | Cards, panels, sidebar |
139
- | `--popover` | `#FFFFFF` | Dropdowns, tooltips, dialogs |
140
- | `--muted` | `#F0F0F0` | Hover states, table headers |
141
- | `--muted-foreground` | `#666666` | Secondary text, placeholders |
142
- | `--primary` | `#B700FF` | Brand accent (CTAs, focus rings) |
143
- | `--primary-foreground` | `#FFFFFF` | Text on primary backgrounds |
144
- | `--destructive` | `#FF3D57` | Errors, delete actions |
145
- | `--success` | `#00E676` | Positive states |
146
- | `--warning` | `#FFB300` | Caution states |
147
- | `--info` | `#40C4FF` | Informational emphasis |
148
- | `--border` | `#E0E0E0` | All structural borders |
149
- | `--ring` | `#B700FF` | Focus ring color |
150
- | `--radius` | `0px` | Border radius (0 = brutalist) |
151
-
152
- ### Dark Theme (`.dark` class)
153
-
154
- Dark mode uses the `.dark` class on the root element. Key overrides:
155
-
156
- | Variable | Dark Value |
157
- | -------------- | ---------- |
158
- | `--background` | `#0A0A0A` |
159
- | `--foreground` | `#FFFFFF` |
160
- | `--card` | `#111111` |
161
- | `--border` | `#333333` |
162
- | `--muted` | `#1A1A1A` |
153
+ The full source of truth is `packages/admin/DESIGN.md`. Key defaults:
154
+
155
+ | Role | Dark | Light |
156
+ | ------------- | --------- | --------- |
157
+ | Background | `#121212` | `#fafafa` |
158
+ | Foreground | `#ececec` | `#1c1c1c` |
159
+ | Card | `#1b1b1b` | `#ffffff` |
160
+ | Surface high | `#2a2a2a` | `#e8e8e8` |
161
+ | Border | `#343434` | `#e2e2e2` |
162
+ | Border subtle | `#262626` | `#ebebeb` |
163
+ | Brand primary | `#b700ff` | `#b700ff` |
164
+
165
+ | Token | Default | Use |
166
+ | ------------------------ | ------- | ------------------------------------------- |
167
+ | `--control-radius-inner` | `8px` | Icon buttons/actions nested inside controls |
168
+ | `--control-radius` | `12px` | Inputs, selects, buttons, compact controls |
169
+ | `--surface-radius` | `14px` | Cards, panels, grouped fields, docs blocks |
170
+ | `--floating-radius` | `14px` | Menus, popovers, dialogs, command panels |
163
171
 
164
172
  ### Typography
165
173
 
166
174
  | Variable | Value |
167
175
  | ------------- | ------------------------------------------------------------------- |
168
- | `--font-sans` | `"Geist Variable"` — body text, descriptions |
169
- | `--font-mono` | `"JetBrains Mono Variable"` — UI chrome: nav, buttons, tabs, badges |
176
+ | `--font-sans` | `"Geist Variable"` — UI, prose, headings, labels, navigation |
177
+ | `--font-mono` | `"JetBrains Mono Variable"` — code, file paths, commands, IDs |
170
178
 
171
179
  ### Sidebar Variables
172
180
 
@@ -184,8 +192,7 @@ Separate tokens for independent sidebar theming: `--sidebar`, `--sidebar-foregro
184
192
  When collections have `.localized()` fields, the admin shows a locale switcher:
185
193
 
186
194
  ```ts title="config/app.ts"
187
- import { appConfig } from "questpie";
188
-
195
+ import { appConfig } from "questpie/app";
189
196
  export default appConfig({
190
197
  locale: {
191
198
  locales: [
@@ -1503,6 +1510,6 @@ toast.error("Failed to save");
1503
1510
 
1504
1511
  6. **MEDIUM: Using `@phosphor-icons/react` or `lucide-react`** — use `@iconify/react` with `ph:` prefix for all icons.
1505
1512
 
1506
- 7. **LOW: Not using shadcn components** — prefer `<Button>`, `<Card>`, `<Input>` from the shadcn component library instead of raw HTML elements. The admin has a consistent brutalist design system.
1513
+ 7. **LOW: Not using shadcn components** — prefer `<Button>`, `<Card>`, `<Input>` from the shadcn component library instead of raw HTML elements. The admin follows QUESTPIE Neutral Design.
1507
1514
 
1508
1515
  ---
@@ -29,7 +29,8 @@ For the complete admin reference with all topics expanded: `AGENTS.md`
29
29
  - **@base-ui/react** primitives (NOT @radix-ui)
30
30
  - **@iconify/react** with Phosphor icon set (`ph:icon-name`)
31
31
  - **sonner** for toasts — `toast.error()`, `toast.success()`
32
- - Brutalist flat design: `--radius: 0px`, no shadows
32
+ - QUESTPIE Neutral Design: flat surfaces, soft neutral geometry,
33
+ tokenized radius, and restrained floating shadows
33
34
 
34
35
  ## Setup
35
36
 
@@ -42,8 +43,7 @@ bun add @questpie/admin
42
43
  ### 2. Runtime Config
43
44
 
44
45
  ```ts title="questpie.config.ts"
45
- import { runtimeConfig } from "questpie";
46
-
46
+ import { runtimeConfig } from "questpie/app";
47
47
  export default runtimeConfig({
48
48
  app: { url: process.env.APP_URL || "http://localhost:3000" },
49
49
  db: { url: process.env.DATABASE_URL },
@@ -56,7 +56,8 @@ The admin module contributes the codegen plugin automatically. It discovers `con
56
56
  ### 3. Modules
57
57
 
58
58
  ```ts title="modules.ts"
59
- import { adminModule, auditModule } from "@questpie/admin/server";
59
+ import { adminModule } from "@questpie/admin/modules/admin";
60
+ import { auditModule } from "@questpie/admin/modules/audit";
60
61
 
61
62
  export default [adminModule, auditModule] as const;
62
63
  ```
@@ -66,6 +67,26 @@ export default [adminModule, auditModule] as const;
66
67
  | `adminModule` | User collection, auth pages, admin UI |
67
68
  | `auditModule` | Audit log collection, timeline widget |
68
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
+
69
90
  ### 4. Admin Config
70
91
 
71
92
  ```ts title="config/admin.ts"
@@ -138,44 +159,31 @@ export default adminConfig({
138
159
 
139
160
  The admin uses CSS variables for all theming. Override them in your own CSS file.
140
161
 
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` |
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 |
172
180
 
173
181
  ### Typography
174
182
 
175
183
  | Variable | Value |
176
184
  | ------------- | ------------------------------------------------------------------- |
177
- | `--font-sans` | `"Geist Variable"` — body text, descriptions |
178
- | `--font-mono` | `"JetBrains Mono Variable"` — UI chrome: nav, buttons, tabs, badges |
185
+ | `--font-sans` | `"Geist Variable"` — UI, prose, headings, labels, navigation |
186
+ | `--font-mono` | `"JetBrains Mono Variable"` — code, file paths, commands, IDs |
179
187
 
180
188
  ### Sidebar Variables
181
189
 
@@ -193,8 +201,7 @@ Separate tokens for independent sidebar theming: `--sidebar`, `--sidebar-foregro
193
201
  When collections have `.localized()` fields, the admin shows a locale switcher:
194
202
 
195
203
  ```ts title="config/app.ts"
196
- import { appConfig } from "questpie";
197
-
204
+ import { appConfig } from "questpie/app";
198
205
  export default appConfig({
199
206
  locale: {
200
207
  locales: [
@@ -302,4 +302,4 @@ toast.error("Failed to save");
302
302
 
303
303
  6. **MEDIUM: Using `@phosphor-icons/react` or `lucide-react`** — use `@iconify/react` with `ph:` prefix for all icons.
304
304
 
305
- 7. **LOW: Not using shadcn components** — prefer `<Button>`, `<Card>`, `<Input>` from the shadcn component library instead of raw HTML elements. The admin has a consistent brutalist design system.
305
+ 7. **LOW: Not using shadcn components** — prefer `<Button>`, `<Card>`, `<Input>` from the shadcn component library instead of raw HTML elements. The admin follows QUESTPIE Neutral Design.
@@ -124,6 +124,12 @@ src/
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`.
126
126
 
127
+ ### Admin User Contract
128
+
129
+ `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` (`admin` or `user`).
130
+
131
+ Do **not** create a replacement `collection("user")` from scratch. If you need custom user fields or admin layout, merge `starterModule.collections.user` or `adminModule.collections.user` and extend it. Replacing the user collection breaks admin setup/login.
132
+
127
133
  ## How To Write Code
128
134
 
129
135
  ### Creating a Collection
@@ -160,7 +166,7 @@ export const posts = collection("posts")
160
166
  { value: "tutorial", label: "Tutorial" },
161
167
  ])
162
168
  .label("Category")
163
- author: f.relation("users").label("Author"),
169
+ author: f.relation("user").label("Author"),
164
170
  image: f.upload().label("Cover Image"),
165
171
  }))
166
172
  .title(({ f }) => f.title)
@@ -194,12 +200,12 @@ Then (preferred):
194
200
 
195
201
  1. Use `bun questpie add collection <name>` to scaffold files
196
202
  2. Codegen runs automatically
197
- 3. Run `bun run migrate:create` to generate migration
203
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
198
204
 
199
205
  Manual workflow (if you create files yourself):
200
206
 
201
207
  1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
202
- 2. Run `bun run migrate:create` to generate migration
208
+ 2. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
203
209
 
204
210
  Collections are auto-discovered by codegen — no manual registration needed.
205
211
 
@@ -233,12 +239,12 @@ Then (preferred):
233
239
 
234
240
  1. Use `bun questpie add global <name>` to scaffold files
235
241
  2. Codegen runs automatically
236
- 3. Run `bun run migrate:create`
242
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
237
243
 
238
244
  Manual workflow (if you create files yourself):
239
245
 
240
246
  1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
241
- 2. Run `bun run migrate:create`
247
+ 2. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
242
248
 
243
249
  Globals are auto-discovered by codegen — no manual registration needed.
244
250
 
@@ -250,7 +256,7 @@ Routes are defined as standalone files in `routes/` and auto-discovered by codeg
250
256
 
251
257
  ```ts
252
258
  // src/questpie/server/routes/get-stats.ts
253
- import { route } from "questpie";
259
+ import { route } from "questpie/services";
254
260
  import { z } from "zod";
255
261
 
256
262
  export default route()
@@ -384,7 +390,7 @@ If your blocks only use declarative prefetch (`{ with: { field: true } }`), you
384
390
 
385
391
  Fields support reactive behaviors in `meta.admin`:
386
392
 
387
- - **`hidden`**: Conditionally hide — `({ data }: { data: Record<string, any> }) => !data.isPublished`
393
+ - **`hidden`**: Conditionally hide — `({ data }: { data: Record<string, unknown> }) => !data.isPublished`
388
394
  - **`readOnly`**: Make read-only based on conditions
389
395
  - **`disabled`**: Disable conditionally
390
396
  - **`compute`**: Auto-compute values — `{ handler, deps, debounce }`
@@ -457,7 +463,7 @@ export const {
457
463
 
458
464
  ```ts
459
465
  // src/routes/api/$.ts
460
- import { createFetchHandler } from "questpie";
466
+ import { createFetchHandler } from "questpie/http";
461
467
  import { app } from "#questpie";
462
468
 
463
469
  const handler = createFetchHandler(app, { basePath: "/api" });
@@ -498,6 +504,7 @@ Optional (with defaults):
498
504
  bun dev # Start dev server
499
505
  bun build # Build for production
500
506
  bun start # Start production server
507
+ bun run db:push # Push schema to local dev database
501
508
  bun run migrate # Run database migrations
502
509
  bun run migrate:create # Create new migration
503
510
  bun run routes:generate # Regenerate TanStack Router route tree
@@ -15,6 +15,7 @@ This is a [QUESTPIE](https://questpie.com) project scaffolded with `create-quest
15
15
  | `bun run questpie:generate` | Regenerate .generated/index.ts |
16
16
  | `bun run scaffold:generate` | Regenerate route tree and QUESTPIE output |
17
17
  | `bun run scaffold:verify` | Regenerate codegen and type-check |
18
+ | `bun run db:push` | Push schema to local dev database |
18
19
  | `bun run migrate:create` | Generate a migration from schema diff |
19
20
  | `bun run migrate` | Run pending migrations |
20
21
  | `bun questpie seed` | Run pending seeds |
@@ -62,6 +63,12 @@ src/questpie/
62
63
  - **`questpie.config.ts`** — CLI config (migration directory, app reference).
63
64
  - **`src/routes/api/$.ts`** — API catch-all handler. Serves REST + OpenAPI docs at `/api/docs`.
64
65
 
66
+ ## Admin User Contract
67
+
68
+ `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` (`admin` or `user`).
69
+
70
+ Do **not** create a replacement `collection("user")` from scratch. If you need custom user fields or admin layout, merge `starterModule.collections.user` or `adminModule.collections.user` and extend it. Replacing the user collection breaks admin setup/login.
71
+
65
72
  ## Environment Variables
66
73
 
67
74
  Defined in `src/lib/env.ts` with runtime validation. See `.env.example` for all available variables.
@@ -84,7 +91,7 @@ Preferred workflow:
84
91
 
85
92
  1. Run `bun questpie add collection my-thing`
86
93
  2. The CLI creates the file and auto-runs codegen
87
- 3. Run `bun run migrate:create`
94
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
88
95
 
89
96
  Manual workflow:
90
97
 
@@ -94,7 +101,7 @@ Manual workflow:
94
101
  export const myThing = collection("my-thing").fields(({ f }) => ({ ... }));
95
102
  ```
96
103
  2. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
97
- 3. Run `bun run migrate:create` to generate migration
104
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
98
105
 
99
106
  Collections are auto-discovered by codegen — no manual registration needed.
100
107
 
@@ -104,20 +111,20 @@ Preferred workflow:
104
111
 
105
112
  1. Run `bun questpie add global my-global`
106
113
  2. The CLI creates the file and auto-runs codegen
107
- 3. Run `bun run migrate:create`
114
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
108
115
 
109
116
  Manual workflow:
110
117
 
111
118
  1. Create `src/questpie/server/globals/my-global.ts` with a named export
112
119
  2. Run `bun run questpie:generate`
113
- 3. Run `bun run migrate:create`
120
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
114
121
 
115
122
  ### Add a server route (end-to-end type-safe)
116
123
 
117
124
  1. Create `src/questpie/server/routes/my-function.ts`:
118
125
 
119
126
  ```ts
120
- import { route } from "questpie";
127
+ import { route } from "questpie/services";
121
128
  import { z } from "zod";
122
129
 
123
130
  export default route()
@@ -18,8 +18,8 @@ docker compose up -d
18
18
  # 2) Regenerate codegen and type-check
19
19
  bun run scaffold:verify
20
20
 
21
- # 3) Run migrations
22
- bun run migrate
21
+ # 3) Create local database tables
22
+ bun run db:push
23
23
 
24
24
  # 4) Start development server
25
25
  bun run dev
@@ -75,6 +75,7 @@ migrations/
75
75
  | `bun run routes:generate` | Regenerate TanStack Router route tree |
76
76
  | `bun run questpie:generate` | Regenerate `src/questpie/server/.generated/*` |
77
77
  | `bun questpie add <type> <name>` | Scaffold entity files (auto-runs codegen) |
78
+ | `bun run db:push` | Push schema directly to local dev database |
78
79
  | `bun run migrate` | Run migrations |
79
80
  | `bun run migrate:create` | Create migration |
80
81
 
@@ -84,14 +85,14 @@ Preferred workflow:
84
85
 
85
86
  1. Run `bun questpie add collection products`.
86
87
  2. The CLI creates the file and runs codegen automatically.
87
- 3. Run `bun run migrate:create`.
88
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
88
89
 
89
90
  Manual workflow (when you create files by hand):
90
91
 
91
92
  1. Create a file in `src/questpie/server/collections/`.
92
93
  2. Export a collection builder from that file.
93
94
  3. Run `bun run questpie:generate`.
94
- 4. Run `bun run migrate:create`.
95
+ 4. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
95
96
 
96
97
  Collections are discovered automatically by codegen. No manual `app.ts` registration is required.
97
98
 
@@ -101,13 +102,13 @@ Preferred workflow:
101
102
 
102
103
  1. Run `bun questpie add global marketing`.
103
104
  2. The CLI creates the file and runs codegen automatically.
104
- 3. Run `bun run migrate:create`.
105
+ 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
105
106
 
106
107
  Manual workflow (when you create files by hand):
107
108
 
108
109
  1. Create a file in `src/questpie/server/globals/`.
109
110
  2. Export a global builder from that file.
110
111
  3. Run `bun run questpie:generate`.
111
- 4. Run `bun run migrate:create`.
112
+ 4. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
112
113
 
113
114
  Globals are discovered automatically by codegen. No manual `app.ts` registration is required.
@@ -15,6 +15,7 @@
15
15
  "routes:generate": "tsr generate",
16
16
  "questpie:generate": "questpie generate -c src/questpie/server/questpie.config.ts",
17
17
  "scaffold:generate": "bun run routes:generate && bun run questpie:generate",
18
+ "db:push": "questpie push -c questpie.config.ts",
18
19
  "migrate": "questpie migrate -c questpie.config.ts",
19
20
  "migrate:create": "questpie migrate:create -c questpie.config.ts",
20
21
  "migrate:status": "questpie migrate:status -c questpie.config.ts",
@@ -1 +1,3 @@
1
- export { default } from "@questpie/admin/client-module";
1
+ import { adminClientModule } from "@questpie/admin/client/modules/admin";
2
+
3
+ export default [adminClientModule] as const;