create-questpie 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/index.mjs +544 -87
  2. package/package.json +2 -3
  3. package/templates/elysia/AGENTS.md +56 -0
  4. package/templates/elysia/CLAUDE.md +39 -0
  5. package/templates/elysia/Dockerfile +24 -0
  6. package/templates/elysia/README.md +148 -0
  7. package/templates/elysia/docker/init-extensions.sql +11 -0
  8. package/templates/elysia/docker-compose.yml +21 -0
  9. package/templates/elysia/env.example +16 -0
  10. package/templates/elysia/gitignore +6 -0
  11. package/templates/elysia/package.json +47 -0
  12. package/templates/elysia/questpie.config.ts +12 -0
  13. package/templates/elysia/src/index.ts +21 -0
  14. package/templates/elysia/src/lib/auth-client.ts +32 -0
  15. package/templates/elysia/src/lib/client.ts +13 -0
  16. package/templates/elysia/src/lib/env.ts +24 -0
  17. package/templates/elysia/src/lib/query-client.ts +18 -0
  18. package/templates/elysia/src/lib/query.ts +18 -0
  19. package/templates/elysia/src/questpie/server/.generated/context.gen.ts +200 -0
  20. package/templates/elysia/src/questpie/server/.generated/entities.gen.ts +84 -0
  21. package/templates/elysia/src/questpie/server/.generated/factories.ts +65 -0
  22. package/templates/elysia/src/questpie/server/.generated/index.ts +131 -0
  23. package/templates/elysia/src/questpie/server/.generated/names.gen.ts +25 -0
  24. package/templates/elysia/src/questpie/server/app.ts +10 -0
  25. package/templates/elysia/src/questpie/server/collections/index.ts +1 -0
  26. package/templates/elysia/src/questpie/server/collections/posts.collection.ts +10 -0
  27. package/templates/elysia/src/questpie/server/config/auth.ts +8 -0
  28. package/templates/elysia/src/questpie/server/config/openapi.ts +10 -0
  29. package/templates/elysia/src/questpie/server/globals/index.ts +1 -0
  30. package/templates/elysia/src/questpie/server/globals/site-settings.global.ts +10 -0
  31. package/templates/elysia/src/questpie/server/modules.ts +8 -0
  32. package/templates/elysia/src/questpie/server/questpie.config.ts +21 -0
  33. package/templates/elysia/tsconfig.json +28 -0
  34. package/templates/hono/AGENTS.md +56 -0
  35. package/templates/hono/CLAUDE.md +39 -0
  36. package/templates/hono/Dockerfile +24 -0
  37. package/templates/hono/README.md +148 -0
  38. package/templates/hono/docker/init-extensions.sql +11 -0
  39. package/templates/hono/docker-compose.yml +21 -0
  40. package/templates/hono/env.example +16 -0
  41. package/templates/hono/gitignore +6 -0
  42. package/templates/hono/package.json +47 -0
  43. package/templates/hono/questpie.config.ts +12 -0
  44. package/templates/hono/src/index.ts +30 -0
  45. package/templates/hono/src/lib/auth-client.ts +32 -0
  46. package/templates/hono/src/lib/client.ts +13 -0
  47. package/templates/hono/src/lib/env.ts +24 -0
  48. package/templates/hono/src/lib/query-client.ts +18 -0
  49. package/templates/hono/src/lib/query.ts +18 -0
  50. package/templates/hono/src/questpie/server/.generated/context.gen.ts +200 -0
  51. package/templates/hono/src/questpie/server/.generated/entities.gen.ts +84 -0
  52. package/templates/hono/src/questpie/server/.generated/factories.ts +65 -0
  53. package/templates/hono/src/questpie/server/.generated/index.ts +131 -0
  54. package/templates/hono/src/questpie/server/.generated/names.gen.ts +25 -0
  55. package/templates/hono/src/questpie/server/app.ts +10 -0
  56. package/templates/hono/src/questpie/server/collections/index.ts +1 -0
  57. package/templates/hono/src/questpie/server/collections/posts.collection.ts +10 -0
  58. package/templates/hono/src/questpie/server/config/auth.ts +8 -0
  59. package/templates/hono/src/questpie/server/config/openapi.ts +10 -0
  60. package/templates/hono/src/questpie/server/globals/index.ts +1 -0
  61. package/templates/hono/src/questpie/server/globals/site-settings.global.ts +10 -0
  62. package/templates/hono/src/questpie/server/modules.ts +8 -0
  63. package/templates/hono/src/questpie/server/questpie.config.ts +21 -0
  64. package/templates/hono/tsconfig.json +28 -0
  65. package/templates/next/AGENTS.md +55 -0
  66. package/templates/next/CLAUDE.md +39 -0
  67. package/templates/next/Dockerfile +25 -0
  68. package/templates/next/README.md +148 -0
  69. package/templates/next/components.json +22 -0
  70. package/templates/next/docker/init-extensions.sql +11 -0
  71. package/templates/next/docker-compose.yml +21 -0
  72. package/templates/next/env.example +16 -0
  73. package/templates/next/gitignore +10 -0
  74. package/templates/next/next-env.d.ts +5 -0
  75. package/templates/next/next.config.ts +20 -0
  76. package/templates/next/package.json +54 -0
  77. package/templates/next/postcss.config.mjs +8 -0
  78. package/templates/next/public/.gitkeep +0 -0
  79. package/templates/next/questpie.config.ts +12 -0
  80. package/templates/next/src/app/admin/[[...all]]/page.tsx +34 -0
  81. package/templates/next/src/app/admin/admin.css +4 -0
  82. package/templates/next/src/app/admin/layout.tsx +63 -0
  83. package/templates/next/src/app/api/[...all]/route.ts +24 -0
  84. package/templates/next/src/app/layout.tsx +24 -0
  85. package/templates/next/src/app/not-found.tsx +18 -0
  86. package/templates/next/src/app/page.tsx +74 -0
  87. package/templates/next/src/app/providers.tsx +11 -0
  88. package/templates/next/src/lib/auth-client.ts +12 -0
  89. package/templates/next/src/lib/client.ts +13 -0
  90. package/templates/next/src/lib/env.ts +24 -0
  91. package/templates/next/src/lib/query-client.ts +18 -0
  92. package/templates/next/src/lib/query.ts +18 -0
  93. package/templates/next/src/questpie/admin/.generated/client.ts +13 -0
  94. package/templates/next/src/questpie/admin/admin.ts +9 -0
  95. package/templates/next/src/questpie/admin/modules.ts +3 -0
  96. package/templates/next/src/questpie/server/.generated/context.gen.ts +204 -0
  97. package/templates/next/src/questpie/server/.generated/entities.gen.ts +100 -0
  98. package/templates/next/src/questpie/server/.generated/factories.ts +204 -0
  99. package/templates/next/src/questpie/server/.generated/index.ts +139 -0
  100. package/templates/next/src/questpie/server/.generated/names.gen.ts +31 -0
  101. package/templates/next/src/questpie/server/app.ts +10 -0
  102. package/templates/next/src/questpie/server/collections/index.ts +1 -0
  103. package/templates/next/src/questpie/server/collections/posts.collection.ts +58 -0
  104. package/templates/next/src/questpie/server/config/admin.ts +80 -0
  105. package/templates/next/src/questpie/server/config/auth.ts +8 -0
  106. package/templates/next/src/questpie/server/config/openapi.ts +10 -0
  107. package/templates/next/src/questpie/server/globals/index.ts +1 -0
  108. package/templates/next/src/questpie/server/globals/site-settings.global.ts +19 -0
  109. package/templates/next/src/questpie/server/modules.ts +9 -0
  110. package/templates/next/src/questpie/server/questpie.config.ts +21 -0
  111. package/templates/next/src/styles.css +125 -0
  112. package/templates/next/tsconfig.json +37 -0
  113. package/templates/tanstack-start/AGENTS.md +35 -600
  114. package/templates/tanstack-start/CLAUDE.md +26 -127
  115. package/templates/tanstack-start/README.md +20 -7
  116. package/templates/tanstack-start/docker/init-extensions.sql +11 -0
  117. package/templates/tanstack-start/docker-compose.yml +1 -0
  118. package/templates/tanstack-start/package.json +1 -0
  119. package/templates/tanstack-start/src/lib/auth-client.ts +1 -1
  120. package/templates/tanstack-start/src/lib/client.ts +1 -1
  121. package/templates/tanstack-start/src/lib/query.ts +18 -0
  122. package/templates/tanstack-start/src/questpie/admin/modules.ts +3 -1
  123. package/templates/tanstack-start/src/questpie/server/.generated/factories.ts +10 -9
  124. package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
  125. package/templates/tanstack-start/src/questpie/server/config/auth.ts +1 -1
  126. package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
  127. package/templates/tanstack-start/src/questpie/server/modules.ts +4 -5
  128. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +3 -2
  129. package/templates/tanstack-start/src/routes/__root.tsx +31 -1
  130. package/templates/tanstack-start/src/routes/api/$.ts +2 -3
  131. package/templates/tanstack-start/src/routes/index.tsx +97 -0
  132. package/templates/tanstack-start/vite.config.ts +2 -2
  133. package/skills/questpie/AGENTS.md +0 -2670
  134. package/skills/questpie/SKILL.md +0 -260
  135. package/skills/questpie/references/auth.md +0 -121
  136. package/skills/questpie/references/business-logic.md +0 -550
  137. package/skills/questpie/references/codegen-plugin-api.md +0 -382
  138. package/skills/questpie/references/crud-api.md +0 -378
  139. package/skills/questpie/references/data-modeling.md +0 -493
  140. package/skills/questpie/references/extend.md +0 -557
  141. package/skills/questpie/references/field-types.md +0 -386
  142. package/skills/questpie/references/infrastructure-adapters.md +0 -545
  143. package/skills/questpie/references/multi-tenancy.md +0 -364
  144. package/skills/questpie/references/production.md +0 -475
  145. package/skills/questpie/references/query-operators.md +0 -125
  146. package/skills/questpie/references/quickstart.md +0 -564
  147. package/skills/questpie/references/rules.md +0 -389
  148. package/skills/questpie/references/tanstack-query.md +0 -520
  149. package/skills/questpie-admin/AGENTS.md +0 -1508
  150. package/skills/questpie-admin/SKILL.md +0 -436
  151. package/skills/questpie-admin/references/blocks.md +0 -331
  152. package/skills/questpie-admin/references/custom-ui.md +0 -305
  153. package/skills/questpie-admin/references/views.md +0 -449
@@ -1,620 +1,55 @@
1
1
  # AGENTS.md
2
2
 
3
- Source-of-truth guidance for AI agents working in this QUESTPIE project.
3
+ Guidance for AI agents working in this [QUESTPIE](https://questpie.com) project.
4
4
 
5
- > **Docs for LLMs**: https://questpie.com/llms.txt (sitemap), https://questpie.com/llms-full.txt (full content)
5
+ ## Use the QUESTPIE skills
6
6
 
7
- ## Project Overview
7
+ This project is built on QUESTPIE. Do not work from memory — the framework is
8
+ codegen-driven and the APIs evolve. Lean on the installed skills:
8
9
 
9
- - **Framework**: TanStack Start (React) + Vite + Nitro (Bun preset)
10
- - **QUESTPIE**: QUESTPIE application framework with config-driven admin UI
11
- - **Database**: PostgreSQL (via Drizzle ORM)
12
- - **Styling**: Tailwind CSS v4 + shadcn/ui components
13
- - **Auth**: Better Auth (email/password)
14
- - **Package manager**: Bun
15
- - **Validation**: Zod v4 (NOT v3)
10
+ - **`questpie`** collections, globals, routes, jobs, codegen, auth, business
11
+ logic, the typed client + TanStack Query. Invoke it for any server/data work.
12
+ - **`questpie-admin`** admin UI: views, blocks, custom fields, branding,
13
+ dashboard, live preview. Invoke it for any admin panel work.
16
14
 
17
- ## Documentation & Resources
15
+ Invoke skills by name (the `/skill` convention) — they are commands, not files
16
+ to read.
18
17
 
19
- When you need more context about QUESTPIE APIs, consult these resources in order:
20
-
21
- 1. **LLMs full docs**: https://questpie.com/llms-full.txt — complete documentation in a single LLM-optimized file
22
- 2. **Online docs**: https://questpie.com/docs — browsable documentation
23
- 3. **Local API docs**: http://localhost:3000/api/docs — Scalar UI (available when dev server is running)
24
-
25
- Key documentation pages:
26
-
27
- | Topic | URL |
28
- | -------------------------- | ---------------------------------------------------------------- |
29
- | Getting Started | https://questpie.com/docs/getting-started |
30
- | Project Structure | https://questpie.com/docs/getting-started/project-structure |
31
- | Your First QUESTPIE | https://questpie.com/docs/getting-started/your-first-app |
32
- | Architecture Principles | https://questpie.com/docs/mentality |
33
- | Field Builder | https://questpie.com/docs/server/field-builder |
34
- | Field Types Reference | https://questpie.com/docs/server/field-types |
35
- | Collections | https://questpie.com/docs/server/collections |
36
- | Globals | https://questpie.com/docs/server/globals |
37
- | Relations | https://questpie.com/docs/server/relations |
38
- | Routes | https://questpie.com/docs/backend/business-logic/routes |
39
- | Hooks & Lifecycle | https://questpie.com/docs/server/hooks-and-lifecycle |
40
- | Access Control | https://questpie.com/docs/server/access-control |
41
- | Reactive Fields | https://questpie.com/docs/server/reactive-fields |
42
- | Validation | https://questpie.com/docs/server/validation |
43
- | Localization | https://questpie.com/docs/server/localization |
44
- | Modules & Extensions | https://questpie.com/docs/server/modules-and-extensions |
45
- | Admin Architecture | https://questpie.com/docs/admin |
46
- | Client Builder (qa) | https://questpie.com/docs/admin/client-builder-qa |
47
- | Component Registry | https://questpie.com/docs/admin/component-registry |
48
- | View Registry | https://questpie.com/docs/admin/view-registry-list-and-form |
49
- | Actions System | https://questpie.com/docs/admin/actions-system |
50
- | Blocks System | https://questpie.com/docs/admin/blocks-system |
51
- | Dashboard & Sidebar | https://questpie.com/docs/admin/dashboard-sidebar-branding |
52
- | TanStack Query Integration | https://questpie.com/docs/client/tanstack-query |
53
- | OpenAPI | https://questpie.com/docs/client/openapi |
54
- | Authentication | https://questpie.com/docs/infrastructure/authentication |
55
- | Database & Migrations | https://questpie.com/docs/infrastructure/database-and-migrations |
56
- | Queue & Jobs | https://questpie.com/docs/infrastructure/queue-and-jobs |
57
- | Storage | https://questpie.com/docs/infrastructure/storage |
58
- | Email | https://questpie.com/docs/infrastructure/email |
59
- | Realtime | https://questpie.com/docs/infrastructure/realtime |
60
-
61
- ## Project Structure
62
-
63
- ```
64
- src/
65
- questpie/
66
- server/ ← WHAT: data contracts and behavior
67
- questpie.config.ts ← App config: runtimeConfig({ db, app, ... })
68
- modules.ts ← Module dependencies (adminModule, openApiModule, etc.)
69
- config/ ← Typed configuration files
70
- auth.ts ← authConfig({...}) — Better Auth options
71
- app.ts ← appConfig({ locale, access, hooks, context })
72
- admin.ts ← adminConfig({ sidebar, dashboard, branding, locale })
73
- openapi.ts ← openApiConfig({ info, scalar })
74
- .generated/ ← Codegen output (app instance + App type)
75
- index.ts
76
- collections/ ← One file per collection (auto-discovered)
77
- globals/ ← One file per global (auto-discovered)
78
- routes/ ← Server routes via route() (auto-discovered)
79
- jobs/ ← Background job definitions (auto-discovered)
80
- blocks/ ← Block definitions (auto-discovered)
81
- admin/ ← HOW: UI rendering concerns
82
- admin.ts ← Re-exports generated admin config
83
- hooks.ts ← Typed hooks via createTypedHooks<App>()
84
- .generated/ ← Codegen output (admin client config)
85
- client.ts
86
- blocks/ ← Block renderers (if using blocks)
87
- lib/
88
- env.ts ← Type-safe env vars (@t3-oss/env-core + Zod)
89
- client.ts ← client instance
90
- routes/
91
- api/$.ts ← QUESTPIE catch-all handler (REST + OpenAPI + auth)
92
- migrations/ ← Database migrations (generated by CLI)
93
- ```
94
-
95
- ## Architecture Rules
96
-
97
- ### Server-First Split
98
-
99
- | Directory | Responsibility | Defines |
100
- | ------------------ | --------------------------------- | ----------------------------------- |
101
- | `questpie/server/` | **WHAT** — contracts and behavior | Schema, access, hooks, routes, jobs |
102
- | `questpie/admin/` | **HOW** — rendering concerns | Branding, locale, custom renderers |
103
- | `routes/` | **Mounting** — HTTP wiring | Route handlers, no business logic |
104
-
105
- ### File Naming Conventions
106
-
107
- - Collections: `*.ts` in `collections/` (e.g., `posts.ts`) — named exports
108
- - Globals: `*.ts` in `globals/` (e.g., `site-settings.ts`) — named exports
109
- - Routes: `*.ts` in `routes/` (e.g., `get-stats.ts`) — default exports
110
- - Jobs: `*.ts` in `jobs/` (e.g., `send-email.ts`) — default exports
111
- - Blocks: `*.ts` in `blocks/` (e.g., `hero.ts`) — named exports
112
-
113
- ### Key Files
114
-
115
- - **`src/questpie/server/questpie.config.ts`** — App config: `runtimeConfig({ db, app, ... })`.
116
- - **`src/questpie/server/modules.ts`** — Module dependencies: `export default [adminModule, openApiModule] as const`.
117
- - **`src/questpie/server/config/auth.ts`** — Auth config via `authConfig()` factory.
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.
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 `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
- - **`src/lib/env.ts`** — Type-safe env variables via `@t3-oss/env-core`. Add new env vars here with Zod schemas.
124
- - **`questpie.config.ts`** — CLI config (migration directory, app reference).
125
- - **`src/routes/api/$.ts`** — API catch-all handler. Serves REST + OpenAPI docs at `/api/docs`.
126
-
127
- ## How To Write Code
128
-
129
- ### Creating a Collection
130
-
131
- Keep the entire builder chain in one file — single source of truth per entity:
132
-
133
- ```ts
134
- // src/questpie/server/collections/posts.ts
135
- import { collection } from "#questpie/factories";
136
-
137
- export const posts = collection("posts")
138
- .fields(({ f }) => ({
139
- title: f.text(255).label("Title").required(),
140
- slug: f
141
- .text(255)
142
- .label("Slug")
143
- .required()
144
- .inputOptional()
145
- .admin({
146
- compute: {
147
- handler: ({ data, prev }) => {
148
- /* slugify title */
149
- },
150
- deps: ({ data }) => [data.title],
151
- debounce: 300,
152
- },
153
- }),
154
- content: f.richText().label("Content"),
155
- published: f.boolean().label("Published").default(false),
156
- category: f
157
- .select([
158
- { value: "news", label: "News" },
159
- { value: "blog", label: "Blog" },
160
- { value: "tutorial", label: "Tutorial" },
161
- ])
162
- .label("Category")
163
- author: f.relation("users").label("Author"),
164
- image: f.upload().label("Cover Image"),
165
- }))
166
- .title(({ f }) => f.title)
167
- .admin(({ c }) => ({
168
- label: "Posts",
169
- icon: c.icon("ph:article"),
170
- }))
171
- .access({
172
- read: true,
173
- create: ({ session }) => !!session,
174
- update: ({ session }) => !!session,
175
- delete: ({ session }) => session?.user?.role === "admin",
176
- })
177
- .hooks({
178
- beforeCreate: [
179
- async ({ data, ctx }) => {
180
- /* ... */ return data;
181
- },
182
- ],
183
- })
184
- .list(({ v }) => v.collectionTable({}))
185
- .form(({ v, f }) =>
186
- v.collectionForm({
187
- sidebar: { position: "right", fields: [f.slug, f.published, f.category] },
188
- fields: [f.title, f.content, f.author, f.image],
189
- }),
190
- );
191
- ```
192
-
193
- Then (preferred):
194
-
195
- 1. Use `bun questpie add collection <name>` to scaffold files
196
- 2. Codegen runs automatically
197
- 3. Run `bun run migrate:create` to generate migration
198
-
199
- Manual workflow (if you create files yourself):
200
-
201
- 1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
202
- 2. Run `bun run migrate:create` to generate migration
203
-
204
- Collections are auto-discovered by codegen — no manual registration needed.
205
-
206
- ### Available Field Types
207
-
208
- **Core:** `text`, `number`, `boolean`, `date`, `datetime`, `time`, `select`, `relation`, `upload`, `object`, `json`, `from`, `email`, `url`, `textarea`.
209
- **Admin module:** `richText`, `blocks` (provided by `@questpie/admin`)
210
-
211
- ### Creating a Global
212
-
213
- ```ts
214
- // src/questpie/server/globals/site-settings.ts
215
- import { global } from "#questpie/factories";
216
-
217
- export const siteSettings = global("siteSettings")
218
- .fields(({ f }) => ({
219
- siteName: f.text(255).label("Site Name").required(),
220
- description: f.textarea().label("Description"),
221
- logo: f.upload().label("Logo"),
222
- maintenanceMode: f.boolean().label("Maintenance Mode").default(false),
223
- }))
224
- .admin(({ c }) => ({ label: "Site Settings", icon: c.icon("ph:gear") }))
225
- .form(({ v, f }) =>
226
- v.globalForm({
227
- fields: [f.siteName, f.description, f.logo, f.maintenanceMode],
228
- }),
229
- );
230
- ```
231
-
232
- Then (preferred):
233
-
234
- 1. Use `bun questpie add global <name>` to scaffold files
235
- 2. Codegen runs automatically
236
- 3. Run `bun run migrate:create`
237
-
238
- Manual workflow (if you create files yourself):
239
-
240
- 1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
241
- 2. Run `bun run migrate:create`
242
-
243
- Globals are auto-discovered by codegen — no manual registration needed.
244
-
245
- ### Creating a Server Route (End-to-End Type-Safe)
246
-
247
- Routes are defined as standalone files in `routes/` and auto-discovered by codegen.
248
-
249
- **Step 1 — Define a route:**
250
-
251
- ```ts
252
- // src/questpie/server/routes/get-stats.ts
253
- import { route } from "questpie";
254
- import { z } from "zod";
255
-
256
- export default route()
257
- .post()
258
- .schema(
259
- z.object({
260
- period: z.enum(["day", "week", "month"]),
261
- }),
262
- )
263
- .handler(async ({ input, collections }) => {
264
- // input: typed from Zod schema; collections, db, session, etc. from AppContext
265
- const count = await collections.posts.count({});
266
- return { totalPosts: count, period: input.period };
267
- });
268
- ```
269
-
270
- **Step 2 — Run codegen:**
18
+ **If those skills are NOT installed**, install them first, then trim this file:
271
19
 
272
20
  ```bash
273
- bun run questpie:generate
274
- ```
275
-
276
- The route is auto-discovered and available at `/api/get-stats`.
277
-
278
- **With access control:**
279
-
280
- ```ts
281
- export default route()
282
- .post()
283
- .schema(z.object({ ... }))
284
- .handler(async ({ input, session }) => {
285
- if (session?.user?.role !== "admin") throw new Error("Forbidden");
286
- return { ok: true };
287
- });
288
- ```
289
-
290
- **With TanStack Query:**
291
-
292
- ```ts
293
- import { useQuery } from "@tanstack/react-query";
294
-
295
- const { data } = useQuery({
296
- queryKey: ["stats", period],
297
- queryFn: () => client.routes.getStats({ period }),
298
- });
299
- ```
300
-
301
- ### Blocks (Page Builder)
302
-
303
- Blocks are content building units for page builders and rich content areas.
304
-
305
- **Simple block (no data fetching):**
306
-
307
- ```ts
308
- // src/questpie/server/blocks/hero.ts
309
- import { block } from "#questpie/factories";
310
-
311
- export const heroBlock = block("hero")
312
- .admin(({ c }) => ({
313
- label: "Hero Section",
314
- icon: c.icon("ph:image"),
315
- category: { label: "Sections", icon: c.icon("ph:layout"), order: 1 },
316
- }))
317
- .fields(({ f }) => ({
318
- title: f.text(255).label("Title").required(),
319
- subtitle: f.textarea().label("Subtitle"),
320
- backgroundImage: f.upload().label("Background Image"),
321
- ctaText: f.text(255).label("CTA Text"),
322
- ctaLink: f.text(255).label("CTA Link"),
323
- }))
324
- .prefetch({ with: { backgroundImage: true } }); // expand upload to full URL
325
- ```
326
-
327
- **Block with dynamic data fetching (prefetch):**
328
-
329
- ```ts
330
- const teamBlock = block("team")
331
- .admin(({ c }) => ({
332
- label: "Team",
333
- icon: c.icon("ph:users"),
334
- category: { label: "Sections", icon: c.icon("ph:layout"), order: 1 },
335
- }))
336
- .fields(({ f }) => ({
337
- title: f.text(255).label("Title"),
338
- limit: f.number().label("Number to Show").default(4),
339
- }))
340
- .prefetch(async ({ values, ctx }) => {
341
- const res = await ctx.collections.members.find({
342
- limit: values.limit || 4,
343
- where: { isActive: true },
344
- with: { avatar: true },
345
- });
346
- return { members: res.docs };
347
- });
348
- ```
349
-
350
- Blocks in `blocks/` are auto-discovered by codegen. No manual registration needed.
351
-
352
- **Use blocks in a collection's richText field:**
353
-
354
- ```ts
355
- content: f.richText().label("Content").blocks([heroBlock, teamBlock]);
356
- ```
357
-
358
- #### Blocks & Circular Dependencies
359
-
360
- Block prefetch handlers receive `ctx` with fully typed `collections` and `globals` via `AppContext` augmentation. Use `ctx.collections.*` directly — no app import needed:
361
-
362
- ```ts
363
- // blocks/latest-posts.ts
364
- import { block } from "#questpie/factories";
365
-
366
- export const latestPostsBlock = block("latest-posts")
367
- .fields(({ f }) => ({
368
- count: f.number().label("Number of Posts").default(3),
369
- }))
370
- .prefetch(async ({ values, ctx }) => {
371
- const res = await ctx.collections.posts.find({
372
- limit: values.count || 3,
373
- where: { published: true },
374
- });
375
- return { posts: res.docs };
376
- });
377
- ```
378
-
379
- Do NOT import `app` from `#questpie` inside block files — these are imported BY `.generated/index.ts`, creating circular dependencies. Use the `ctx` parameters instead.
380
-
381
- If your blocks only use declarative prefetch (`{ with: { field: true } }`), you don't need a function at all.
382
-
383
- ### Reactive Fields
384
-
385
- Fields support reactive behaviors in `meta.admin`:
386
-
387
- - **`hidden`**: Conditionally hide — `({ data }: { data: Record<string, any> }) => !data.isPublished`
388
- - **`readOnly`**: Make read-only based on conditions
389
- - **`disabled`**: Disable conditionally
390
- - **`compute`**: Auto-compute values — `{ handler, deps, debounce }`
391
-
392
- All reactive handlers run **server-side** with access to `ctx.db`, `ctx.user`, `ctx.req`.
393
-
394
- ```ts
395
- fields: ({ f }) => ({
396
- country: f.relation("countries").label("Country"),
397
- city: f
398
- .relation("cities")
399
- .label("City")
400
- .admin({
401
- options: {
402
- handler: async ({ data, search, ctx }) => {
403
- const cities = await ctx.db.query.cities.findMany({
404
- where: { countryId: data.country },
405
- });
406
- return {
407
- options: cities.map((c) => ({ value: c.id, label: c.name })),
408
- };
409
- },
410
- deps: ({ data }) => [data.country],
411
- },
412
- }),
413
- status: f
414
- .select([
415
- { value: "draft", label: "Draft" },
416
- { value: "published", label: "Published" },
417
- { value: "archived", label: "Archived" },
418
- ])
419
- .label("Status")
420
- publishedAt: f
421
- .datetime()
422
- .label("Published At")
423
- .admin({
424
- hidden: ({ data }) => data.status !== "published",
425
- }),
426
- });
427
- ```
428
-
429
- ### Admin Configuration (Client-Side)
430
-
431
- The admin client config is auto-generated by codegen into `admin/.generated/client.ts`.
432
- No manual builder setup is needed. Run `bun run questpie:generate` to regenerate.
433
-
434
- ```ts
435
- // src/questpie/admin/admin.ts (re-export for convenience)
436
- export { default as admin } from "./.generated/client";
21
+ bunx skills add questpie/questpie
437
22
  ```
438
23
 
439
- ```ts
440
- // src/questpie/admin/hooks.ts
441
- import { createTypedHooks } from "@questpie/admin/client";
442
- import type { App } from "#questpie";
443
-
444
- export const {
445
- useCollectionList,
446
- useCollectionCount,
447
- useCollectionItem,
448
- useCollectionCreate,
449
- useCollectionUpdate,
450
- useCollectionDelete,
451
- useGlobal,
452
- useGlobalUpdate,
453
- } = createTypedHooks<App>();
454
- ```
455
-
456
- ### QUESTPIE Route Handler
457
-
458
- ```ts
459
- // src/routes/api/$.ts
460
- import { createFetchHandler } from "questpie";
461
- import { app } from "#questpie";
462
-
463
- const handler = createFetchHandler(app, { basePath: "/api" });
464
- ```
465
-
466
- OpenAPI is registered as a module in `src/questpie/server/modules.ts` via `openApiModule` — no wrapper needed in the route handler.
467
-
468
- ### Icons
24
+ After installing, replace the body of this file with a one-line pointer to the
25
+ skills above — they are the always-current source of truth and this doc should
26
+ not duplicate them.
469
27
 
470
- Use `@iconify/react` with Phosphor icon set:
28
+ ## Docs for LLMs
471
29
 
472
- - Prefix: `ph:` (e.g., `ph:house`, `ph:article`, `ph:gear`)
473
- - Weight variants: `-bold`, `-fill`, `-duotone`, `-light`, `-thin`
474
- - Regular weight = no suffix (default)
475
- - Naming: PascalCase → kebab-case (e.g., `CaretDown` → `ph:caret-down`)
476
- - In server/admin config, use `c.icon("ph:icon-name")`
30
+ When a skill isn't enough, consult:
477
31
 
478
- ## Environment Variables
32
+ - https://questpie.com/llms.txt — doc sitemap
33
+ - https://questpie.com/llms-full.txt — full docs in one LLM-optimized file
34
+ - http://localhost:3000/api/docs — live API reference (Scalar, dev server running)
479
35
 
480
- Type-safe via `@t3-oss/env-core` in `src/lib/env.ts`. All env vars must be:
36
+ ## This project
481
37
 
482
- 1. Declared with Zod schema in `env.ts`
483
- 2. Accessed via `env.VAR_NAME` (not `process.env.VAR_NAME`)
38
+ - **Runtime**: TanStack Start (React) + Vite + Nitro, package manager **Bun**
39
+ - **Database**: PostgreSQL via Drizzle ORM (Postgres extensions are not
40
+ auto-created — see `README.md`)
41
+ - **Auth**: Better Auth (email/password); the `user` collection ships with
42
+ admin — extend it, never replace it
43
+ - **Validation**: Zod **v4** (not v3)
44
+ - **Source layout**: server contracts in `src/questpie/server/`, admin UI in
45
+ `src/questpie/admin/`, HTTP mount in `src/routes/api/$.ts`, typed client in
46
+ `src/lib/`
484
47
 
485
- Required:
486
-
487
- - `DATABASE_URL` — PostgreSQL connection string
488
-
489
- Optional (with defaults):
490
-
491
- - `APP_URL` — Application URL (default: `http://localhost:3000`)
492
- - `BETTER_AUTH_SECRET` — Auth secret key
493
- - `MAIL_ADAPTER` — `console` or `smtp`
494
-
495
- ## Commands
48
+ ## Key scripts
496
49
 
497
50
  ```bash
498
- bun dev # Start dev server
499
- bun build # Build for production
500
- bun start # Start production server
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
507
- docker compose up -d # Start PostgreSQL
51
+ bun dev # Start dev server (port 3000)
52
+ bun run scaffold:verify # Regenerate codegen + type-check
53
+ bun run db:push # Push schema to the local dev database
54
+ bun questpie add collection <name> # Scaffold an entity (auto-runs codegen)
508
55
  ```
509
-
510
- ## Critical Dependencies
511
-
512
- Always use these exact versions — check `package.json` before upgrading:
513
-
514
- | Package | Version | Notes |
515
- | ---------------- | ------- | -------------------- |
516
- | `zod` | `^4.x` | **v4 ONLY** — not v3 |
517
- | `drizzle-orm` | `beta` | Specific beta build |
518
- | `react` | `^19.x` | React 19 |
519
- | `tailwindcss` | `^4.x` | Tailwind CSS v4 |
520
- | `@base-ui/react` | `^1.x` | NOT @radix-ui |
521
-
522
- ## Anti-Patterns
523
-
524
- - **Schema rules in client code** — Validation, access control, and hooks belong on the server.
525
- - **Splitting a collection across files** — Keep the full `.collection().fields().admin().list().form()` chain in one file.
526
- - **Business logic in route handlers** — Mounting files should only mount handlers. Business logic goes in server routes, hooks, or jobs.
527
- - **Hardcoding view components** — Use the registry pattern for custom views.
528
- - **Using `process.env` directly** — Use the `env` object from `src/lib/env.ts`.
529
- - **Using Zod v3 API** — This project uses Zod v4. Use `z.object()` etc. from `zod` (v4).
530
- - **Using `asChild` prop** — This project uses `@base-ui/react`, not Radix. Use `render` prop instead.
531
- - **Using Radix UI or Lucide icons** — Use `@base-ui/react` and `@iconify/react` with `ph:` prefix.
532
- - **Adding UI config to database schema** — Admin UI config is UI-only, defined in builder chain.
533
- - **Importing `app` from `#questpie` in blocks/collections/hooks** — Files inside `collections/`, `globals/`, `routes/`, `hooks/`, `blocks/` are imported BY `.generated/index.ts`, so importing from it back creates circular dependencies. Use the `ctx` parameters instead.
534
-
535
- ## Live Preview
536
-
537
- QUESTPIE supports live preview with a split-screen editor. The current implementation refreshes the preview iframe after save/autosave and uses `postMessage` for field/block focus sync.
538
-
539
- ### Key Principles
540
-
541
- - **Same-tab preview** = iframe refresh after save/autosave plus `postMessage` focus events
542
- - **Frontend hook** = `useCollectionPreview({ initialData, onRefresh })`
543
- - **Field focus** = `PreviewProvider` + `PreviewField`
544
- - **Block field paths** = `BlockScopeProvider` + `PreviewField`
545
-
546
- ### Server Config
547
-
548
- Add `.preview()` to a collection to enable the split-screen editor:
549
-
550
- ```ts
551
- // src/questpie/server/collections/pages.ts
552
- import { collection } from "#questpie/factories";
553
-
554
- export const pages = collection("pages")
555
- .fields(({ f }) => ({
556
- title: f.text(255).label("Title").required(),
557
- slug: f.text(255).label("Slug").required(),
558
- content: f.blocks().label("Content"),
559
- }))
560
- .preview({
561
- enabled: true,
562
- position: "right",
563
- defaultWidth: 50,
564
- url: ({ record }) => {
565
- const slug = record.slug as string;
566
- return slug === "home" ? "/?preview=true" : `/${slug}?preview=true`;
567
- },
568
- });
569
- ```
570
-
571
- ### Frontend Integration
572
-
573
- Use `useCollectionPreview` in your frontend page components:
574
-
575
- ```tsx
576
- // src/routes/[slug].tsx
577
- import {
578
- PreviewField,
579
- PreviewProvider,
580
- useCollectionPreview,
581
- } from "@questpie/admin/client";
582
-
583
- function PageComponent({ initialData }) {
584
- const router = useRouter();
585
- const preview = useCollectionPreview({
586
- initialData,
587
- onRefresh: () => router.invalidate(),
588
- });
589
-
590
- return (
591
- <PreviewProvider
592
- isPreviewMode={preview.isPreviewMode}
593
- focusedField={preview.focusedField}
594
- onFieldClick={preview.handleFieldClick}
595
- >
596
- <PreviewField field="title" as="h1">
597
- {preview.data.title}
598
- </PreviewField>
599
- </PreviewProvider>
600
- );
601
- }
602
- ```
603
-
604
- #### Protocol
605
-
606
- The implemented preview messages are simple `postMessage` events:
607
-
608
- | Field | Description |
609
- | ----------------- | --------------------------------------- |
610
- | `PREVIEW_READY` | Preview iframe tells admin it is ready |
611
- | `PREVIEW_REFRESH` | Admin asks iframe to refresh data |
612
- | `FIELD_CLICKED` | Preview asks admin to focus a field |
613
- | `BLOCK_CLICKED` | Preview asks admin to select a block |
614
- | `FOCUS_FIELD` | Admin asks preview to highlight a field |
615
- | `SELECT_BLOCK` | Admin asks preview to highlight a block |
616
-
617
- ### Anti-Patterns (Preview)
618
-
619
- - **Using V2-only APIs in this template** — `useQuestpiePreview`, `PreviewRoot`, and `PreviewBlock` are not exported yet.
620
- - **Importing `app` inside previewed collection/block files** — use handler `ctx` values to avoid generated-app cycles.