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.
- package/dist/index.mjs +244 -30
- package/package.json +1 -1
- package/skills/questpie/AGENTS.md +299 -98
- package/skills/questpie/SKILL.md +50 -17
- package/skills/questpie/coverage.json +213 -0
- package/skills/questpie/references/auth.md +119 -4
- package/skills/questpie/references/business-logic.md +126 -56
- package/skills/questpie/references/crud-api.md +231 -29
- package/skills/questpie/references/data-modeling.md +22 -6
- package/skills/questpie/references/extend.md +34 -7
- package/skills/questpie/references/field-types.md +14 -2
- package/skills/questpie/references/infrastructure-adapters.md +207 -32
- package/skills/questpie/references/mcp.md +147 -0
- package/skills/questpie/references/multi-tenancy.md +1 -2
- package/skills/questpie/references/production.md +218 -53
- package/skills/questpie/references/quickstart.md +6 -8
- package/skills/questpie/references/rules.md +86 -21
- package/skills/questpie/references/sandbox.md +110 -0
- package/skills/questpie/references/tanstack-query.md +34 -11
- package/skills/questpie/references/type-inference.md +167 -0
- package/skills/questpie/references/workflows.md +155 -0
- package/skills/questpie-admin/AGENTS.md +47 -40
- package/skills/questpie-admin/SKILL.md +46 -39
- package/skills/questpie-admin/references/custom-ui.md +1 -1
- package/templates/tanstack-start/AGENTS.md +15 -8
- package/templates/tanstack-start/CLAUDE.md +12 -5
- package/templates/tanstack-start/README.md +7 -6
- package/templates/tanstack-start/package.json +1 -0
- package/templates/tanstack-start/src/questpie/admin/modules.ts +3 -1
- package/templates/tanstack-start/src/questpie/server/.generated/factories.ts +10 -9
- package/templates/tanstack-start/src/questpie/server/config/auth.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/modules.ts +4 -5
- package/templates/tanstack-start/src/questpie/server/questpie.config.ts +2 -1
- package/templates/tanstack-start/src/routes/api/$.ts +1 -2
- 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
|
-
-
|
|
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
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
| `--
|
|
147
|
-
| `--
|
|
148
|
-
| `--
|
|
149
|
-
| `--
|
|
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"` —
|
|
169
|
-
| `--font-mono` | `"JetBrains Mono Variable"` —
|
|
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
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
| `--
|
|
156
|
-
| `--
|
|
157
|
-
| `--
|
|
158
|
-
| `--
|
|
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"` —
|
|
178
|
-
| `--font-mono` | `"JetBrains Mono Variable"` —
|
|
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
|
|
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("
|
|
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`
|
|
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`
|
|
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,
|
|
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`
|
|
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)
|
|
22
|
-
bun run
|
|
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",
|