create-questpie 2.0.4 → 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 (152) hide show
  1. package/dist/index.mjs +362 -119
  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 -607
  114. package/templates/tanstack-start/CLAUDE.md +26 -134
  115. package/templates/tanstack-start/README.md +13 -1
  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/src/lib/auth-client.ts +1 -1
  119. package/templates/tanstack-start/src/lib/client.ts +1 -1
  120. package/templates/tanstack-start/src/lib/query.ts +18 -0
  121. package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
  122. package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
  123. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +1 -1
  124. package/templates/tanstack-start/src/routes/__root.tsx +31 -1
  125. package/templates/tanstack-start/src/routes/api/$.ts +1 -1
  126. package/templates/tanstack-start/src/routes/index.tsx +97 -0
  127. package/skills/questpie/AGENTS.md +0 -2871
  128. package/skills/questpie/SKILL.md +0 -293
  129. package/skills/questpie/coverage.json +0 -213
  130. package/skills/questpie/references/auth.md +0 -236
  131. package/skills/questpie/references/business-logic.md +0 -620
  132. package/skills/questpie/references/codegen-plugin-api.md +0 -382
  133. package/skills/questpie/references/crud-api.md +0 -580
  134. package/skills/questpie/references/data-modeling.md +0 -509
  135. package/skills/questpie/references/extend.md +0 -584
  136. package/skills/questpie/references/field-types.md +0 -398
  137. package/skills/questpie/references/infrastructure-adapters.md +0 -720
  138. package/skills/questpie/references/mcp.md +0 -147
  139. package/skills/questpie/references/multi-tenancy.md +0 -363
  140. package/skills/questpie/references/production.md +0 -640
  141. package/skills/questpie/references/query-operators.md +0 -125
  142. package/skills/questpie/references/quickstart.md +0 -562
  143. package/skills/questpie/references/rules.md +0 -454
  144. package/skills/questpie/references/sandbox.md +0 -110
  145. package/skills/questpie/references/tanstack-query.md +0 -543
  146. package/skills/questpie/references/type-inference.md +0 -167
  147. package/skills/questpie/references/workflows.md +0 -155
  148. package/skills/questpie-admin/AGENTS.md +0 -1515
  149. package/skills/questpie-admin/SKILL.md +0 -443
  150. package/skills/questpie-admin/references/blocks.md +0 -331
  151. package/skills/questpie-admin/references/custom-ui.md +0 -305
  152. package/skills/questpie-admin/references/views.md +0 -449
@@ -1,627 +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
- ### 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
-
133
- ## How To Write Code
134
-
135
- ### Creating a Collection
136
-
137
- Keep the entire builder chain in one file — single source of truth per entity:
138
-
139
- ```ts
140
- // src/questpie/server/collections/posts.ts
141
- import { collection } from "#questpie/factories";
142
-
143
- export const posts = collection("posts")
144
- .fields(({ f }) => ({
145
- title: f.text(255).label("Title").required(),
146
- slug: f
147
- .text(255)
148
- .label("Slug")
149
- .required()
150
- .inputOptional()
151
- .admin({
152
- compute: {
153
- handler: ({ data, prev }) => {
154
- /* slugify title */
155
- },
156
- deps: ({ data }) => [data.title],
157
- debounce: 300,
158
- },
159
- }),
160
- content: f.richText().label("Content"),
161
- published: f.boolean().label("Published").default(false),
162
- category: f
163
- .select([
164
- { value: "news", label: "News" },
165
- { value: "blog", label: "Blog" },
166
- { value: "tutorial", label: "Tutorial" },
167
- ])
168
- .label("Category")
169
- author: f.relation("user").label("Author"),
170
- image: f.upload().label("Cover Image"),
171
- }))
172
- .title(({ f }) => f.title)
173
- .admin(({ c }) => ({
174
- label: "Posts",
175
- icon: c.icon("ph:article"),
176
- }))
177
- .access({
178
- read: true,
179
- create: ({ session }) => !!session,
180
- update: ({ session }) => !!session,
181
- delete: ({ session }) => session?.user?.role === "admin",
182
- })
183
- .hooks({
184
- beforeCreate: [
185
- async ({ data, ctx }) => {
186
- /* ... */ return data;
187
- },
188
- ],
189
- })
190
- .list(({ v }) => v.collectionTable({}))
191
- .form(({ v, f }) =>
192
- v.collectionForm({
193
- sidebar: { position: "right", fields: [f.slug, f.published, f.category] },
194
- fields: [f.title, f.content, f.author, f.image],
195
- }),
196
- );
197
- ```
198
-
199
- Then (preferred):
200
-
201
- 1. Use `bun questpie add collection <name>` to scaffold files
202
- 2. Codegen runs automatically
203
- 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
204
-
205
- Manual workflow (if you create files yourself):
206
-
207
- 1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
208
- 2. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
209
-
210
- Collections are auto-discovered by codegen — no manual registration needed.
211
-
212
- ### Available Field Types
213
-
214
- **Core:** `text`, `number`, `boolean`, `date`, `datetime`, `time`, `select`, `relation`, `upload`, `object`, `json`, `from`, `email`, `url`, `textarea`.
215
- **Admin module:** `richText`, `blocks` (provided by `@questpie/admin`)
216
-
217
- ### Creating a Global
218
-
219
- ```ts
220
- // src/questpie/server/globals/site-settings.ts
221
- import { global } from "#questpie/factories";
222
-
223
- export const siteSettings = global("siteSettings")
224
- .fields(({ f }) => ({
225
- siteName: f.text(255).label("Site Name").required(),
226
- description: f.textarea().label("Description"),
227
- logo: f.upload().label("Logo"),
228
- maintenanceMode: f.boolean().label("Maintenance Mode").default(false),
229
- }))
230
- .admin(({ c }) => ({ label: "Site Settings", icon: c.icon("ph:gear") }))
231
- .form(({ v, f }) =>
232
- v.globalForm({
233
- fields: [f.siteName, f.description, f.logo, f.maintenanceMode],
234
- }),
235
- );
236
- ```
237
-
238
- Then (preferred):
239
-
240
- 1. Use `bun questpie add global <name>` to scaffold files
241
- 2. Codegen runs automatically
242
- 3. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
243
-
244
- Manual workflow (if you create files yourself):
245
-
246
- 1. Run `bun run questpie:generate` to regenerate `.generated/index.ts`
247
- 2. Run `bun run db:push` for local development, or `bun run migrate:create` for production migrations.
248
-
249
- Globals are auto-discovered by codegen — no manual registration needed.
250
-
251
- ### Creating a Server Route (End-to-End Type-Safe)
252
-
253
- Routes are defined as standalone files in `routes/` and auto-discovered by codegen.
254
-
255
- **Step 1 — Define a route:**
256
-
257
- ```ts
258
- // src/questpie/server/routes/get-stats.ts
259
- import { route } from "questpie/services";
260
- import { z } from "zod";
261
-
262
- export default route()
263
- .post()
264
- .schema(
265
- z.object({
266
- period: z.enum(["day", "week", "month"]),
267
- }),
268
- )
269
- .handler(async ({ input, collections }) => {
270
- // input: typed from Zod schema; collections, db, session, etc. from AppContext
271
- const count = await collections.posts.count({});
272
- return { totalPosts: count, period: input.period };
273
- });
274
- ```
275
-
276
- **Step 2 — Run codegen:**
18
+ **If those skills are NOT installed**, install them first, then trim this file:
277
19
 
278
20
  ```bash
279
- bun run questpie:generate
21
+ bunx skills add questpie/questpie
280
22
  ```
281
23
 
282
- The route is auto-discovered and available at `/api/get-stats`.
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.
283
27
 
284
- **With access control:**
28
+ ## Docs for LLMs
285
29
 
286
- ```ts
287
- export default route()
288
- .post()
289
- .schema(z.object({ ... }))
290
- .handler(async ({ input, session }) => {
291
- if (session?.user?.role !== "admin") throw new Error("Forbidden");
292
- return { ok: true };
293
- });
294
- ```
295
-
296
- **With TanStack Query:**
297
-
298
- ```ts
299
- import { useQuery } from "@tanstack/react-query";
300
-
301
- const { data } = useQuery({
302
- queryKey: ["stats", period],
303
- queryFn: () => client.routes.getStats({ period }),
304
- });
305
- ```
306
-
307
- ### Blocks (Page Builder)
30
+ When a skill isn't enough, consult:
308
31
 
309
- Blocks are content building units for page builders and rich content areas.
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)
310
35
 
311
- **Simple block (no data fetching):**
36
+ ## This project
312
37
 
313
- ```ts
314
- // src/questpie/server/blocks/hero.ts
315
- import { block } from "#questpie/factories";
316
-
317
- export const heroBlock = block("hero")
318
- .admin(({ c }) => ({
319
- label: "Hero Section",
320
- icon: c.icon("ph:image"),
321
- category: { label: "Sections", icon: c.icon("ph:layout"), order: 1 },
322
- }))
323
- .fields(({ f }) => ({
324
- title: f.text(255).label("Title").required(),
325
- subtitle: f.textarea().label("Subtitle"),
326
- backgroundImage: f.upload().label("Background Image"),
327
- ctaText: f.text(255).label("CTA Text"),
328
- ctaLink: f.text(255).label("CTA Link"),
329
- }))
330
- .prefetch({ with: { backgroundImage: true } }); // expand upload to full URL
331
- ```
332
-
333
- **Block with dynamic data fetching (prefetch):**
334
-
335
- ```ts
336
- const teamBlock = block("team")
337
- .admin(({ c }) => ({
338
- label: "Team",
339
- icon: c.icon("ph:users"),
340
- category: { label: "Sections", icon: c.icon("ph:layout"), order: 1 },
341
- }))
342
- .fields(({ f }) => ({
343
- title: f.text(255).label("Title"),
344
- limit: f.number().label("Number to Show").default(4),
345
- }))
346
- .prefetch(async ({ values, ctx }) => {
347
- const res = await ctx.collections.members.find({
348
- limit: values.limit || 4,
349
- where: { isActive: true },
350
- with: { avatar: true },
351
- });
352
- return { members: res.docs };
353
- });
354
- ```
355
-
356
- Blocks in `blocks/` are auto-discovered by codegen. No manual registration needed.
357
-
358
- **Use blocks in a collection's richText field:**
359
-
360
- ```ts
361
- content: f.richText().label("Content").blocks([heroBlock, teamBlock]);
362
- ```
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/`
363
47
 
364
- #### Blocks & Circular Dependencies
365
-
366
- Block prefetch handlers receive `ctx` with fully typed `collections` and `globals` via `AppContext` augmentation. Use `ctx.collections.*` directly — no app import needed:
367
-
368
- ```ts
369
- // blocks/latest-posts.ts
370
- import { block } from "#questpie/factories";
371
-
372
- export const latestPostsBlock = block("latest-posts")
373
- .fields(({ f }) => ({
374
- count: f.number().label("Number of Posts").default(3),
375
- }))
376
- .prefetch(async ({ values, ctx }) => {
377
- const res = await ctx.collections.posts.find({
378
- limit: values.count || 3,
379
- where: { published: true },
380
- });
381
- return { posts: res.docs };
382
- });
383
- ```
384
-
385
- Do NOT import `app` from `#questpie` inside block files — these are imported BY `.generated/index.ts`, creating circular dependencies. Use the `ctx` parameters instead.
386
-
387
- If your blocks only use declarative prefetch (`{ with: { field: true } }`), you don't need a function at all.
388
-
389
- ### Reactive Fields
390
-
391
- Fields support reactive behaviors in `meta.admin`:
392
-
393
- - **`hidden`**: Conditionally hide — `({ data }: { data: Record<string, unknown> }) => !data.isPublished`
394
- - **`readOnly`**: Make read-only based on conditions
395
- - **`disabled`**: Disable conditionally
396
- - **`compute`**: Auto-compute values — `{ handler, deps, debounce }`
397
-
398
- All reactive handlers run **server-side** with access to `ctx.db`, `ctx.user`, `ctx.req`.
399
-
400
- ```ts
401
- fields: ({ f }) => ({
402
- country: f.relation("countries").label("Country"),
403
- city: f
404
- .relation("cities")
405
- .label("City")
406
- .admin({
407
- options: {
408
- handler: async ({ data, search, ctx }) => {
409
- const cities = await ctx.db.query.cities.findMany({
410
- where: { countryId: data.country },
411
- });
412
- return {
413
- options: cities.map((c) => ({ value: c.id, label: c.name })),
414
- };
415
- },
416
- deps: ({ data }) => [data.country],
417
- },
418
- }),
419
- status: f
420
- .select([
421
- { value: "draft", label: "Draft" },
422
- { value: "published", label: "Published" },
423
- { value: "archived", label: "Archived" },
424
- ])
425
- .label("Status")
426
- publishedAt: f
427
- .datetime()
428
- .label("Published At")
429
- .admin({
430
- hidden: ({ data }) => data.status !== "published",
431
- }),
432
- });
433
- ```
434
-
435
- ### Admin Configuration (Client-Side)
436
-
437
- The admin client config is auto-generated by codegen into `admin/.generated/client.ts`.
438
- No manual builder setup is needed. Run `bun run questpie:generate` to regenerate.
439
-
440
- ```ts
441
- // src/questpie/admin/admin.ts (re-export for convenience)
442
- export { default as admin } from "./.generated/client";
443
- ```
444
-
445
- ```ts
446
- // src/questpie/admin/hooks.ts
447
- import { createTypedHooks } from "@questpie/admin/client";
448
- import type { App } from "#questpie";
449
-
450
- export const {
451
- useCollectionList,
452
- useCollectionCount,
453
- useCollectionItem,
454
- useCollectionCreate,
455
- useCollectionUpdate,
456
- useCollectionDelete,
457
- useGlobal,
458
- useGlobalUpdate,
459
- } = createTypedHooks<App>();
460
- ```
461
-
462
- ### QUESTPIE Route Handler
463
-
464
- ```ts
465
- // src/routes/api/$.ts
466
- import { createFetchHandler } from "questpie/http";
467
- import { app } from "#questpie";
468
-
469
- const handler = createFetchHandler(app, { basePath: "/api" });
470
- ```
471
-
472
- OpenAPI is registered as a module in `src/questpie/server/modules.ts` via `openApiModule` — no wrapper needed in the route handler.
473
-
474
- ### Icons
475
-
476
- Use `@iconify/react` with Phosphor icon set:
477
-
478
- - Prefix: `ph:` (e.g., `ph:house`, `ph:article`, `ph:gear`)
479
- - Weight variants: `-bold`, `-fill`, `-duotone`, `-light`, `-thin`
480
- - Regular weight = no suffix (default)
481
- - Naming: PascalCase → kebab-case (e.g., `CaretDown` → `ph:caret-down`)
482
- - In server/admin config, use `c.icon("ph:icon-name")`
483
-
484
- ## Environment Variables
485
-
486
- Type-safe via `@t3-oss/env-core` in `src/lib/env.ts`. All env vars must be:
487
-
488
- 1. Declared with Zod schema in `env.ts`
489
- 2. Accessed via `env.VAR_NAME` (not `process.env.VAR_NAME`)
490
-
491
- Required:
492
-
493
- - `DATABASE_URL` — PostgreSQL connection string
494
-
495
- Optional (with defaults):
496
-
497
- - `APP_URL` — Application URL (default: `http://localhost:3000`)
498
- - `BETTER_AUTH_SECRET` — Auth secret key
499
- - `MAIL_ADAPTER` — `console` or `smtp`
500
-
501
- ## Commands
48
+ ## Key scripts
502
49
 
503
50
  ```bash
504
- bun dev # Start dev server
505
- bun build # Build for production
506
- bun start # Start production server
507
- bun run db:push # Push schema to local dev database
508
- bun run migrate # Run database migrations
509
- bun run migrate:create # Create new migration
510
- bun run routes:generate # Regenerate TanStack Router route tree
511
- bun run questpie:generate # Regenerate codegen output
512
- bun run scaffold:generate # Regenerate route tree and QUESTPIE output
513
- bun run scaffold:verify # Regenerate codegen and type-check
514
- docker compose up -d # Start PostgreSQL
515
- ```
516
-
517
- ## Critical Dependencies
518
-
519
- Always use these exact versions — check `package.json` before upgrading:
520
-
521
- | Package | Version | Notes |
522
- | ---------------- | ------- | -------------------- |
523
- | `zod` | `^4.x` | **v4 ONLY** — not v3 |
524
- | `drizzle-orm` | `beta` | Specific beta build |
525
- | `react` | `^19.x` | React 19 |
526
- | `tailwindcss` | `^4.x` | Tailwind CSS v4 |
527
- | `@base-ui/react` | `^1.x` | NOT @radix-ui |
528
-
529
- ## Anti-Patterns
530
-
531
- - **Schema rules in client code** — Validation, access control, and hooks belong on the server.
532
- - **Splitting a collection across files** — Keep the full `.collection().fields().admin().list().form()` chain in one file.
533
- - **Business logic in route handlers** — Mounting files should only mount handlers. Business logic goes in server routes, hooks, or jobs.
534
- - **Hardcoding view components** — Use the registry pattern for custom views.
535
- - **Using `process.env` directly** — Use the `env` object from `src/lib/env.ts`.
536
- - **Using Zod v3 API** — This project uses Zod v4. Use `z.object()` etc. from `zod` (v4).
537
- - **Using `asChild` prop** — This project uses `@base-ui/react`, not Radix. Use `render` prop instead.
538
- - **Using Radix UI or Lucide icons** — Use `@base-ui/react` and `@iconify/react` with `ph:` prefix.
539
- - **Adding UI config to database schema** — Admin UI config is UI-only, defined in builder chain.
540
- - **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.
541
-
542
- ## Live Preview
543
-
544
- 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.
545
-
546
- ### Key Principles
547
-
548
- - **Same-tab preview** = iframe refresh after save/autosave plus `postMessage` focus events
549
- - **Frontend hook** = `useCollectionPreview({ initialData, onRefresh })`
550
- - **Field focus** = `PreviewProvider` + `PreviewField`
551
- - **Block field paths** = `BlockScopeProvider` + `PreviewField`
552
-
553
- ### Server Config
554
-
555
- Add `.preview()` to a collection to enable the split-screen editor:
556
-
557
- ```ts
558
- // src/questpie/server/collections/pages.ts
559
- import { collection } from "#questpie/factories";
560
-
561
- export const pages = collection("pages")
562
- .fields(({ f }) => ({
563
- title: f.text(255).label("Title").required(),
564
- slug: f.text(255).label("Slug").required(),
565
- content: f.blocks().label("Content"),
566
- }))
567
- .preview({
568
- enabled: true,
569
- position: "right",
570
- defaultWidth: 50,
571
- url: ({ record }) => {
572
- const slug = record.slug as string;
573
- return slug === "home" ? "/?preview=true" : `/${slug}?preview=true`;
574
- },
575
- });
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)
576
55
  ```
577
-
578
- ### Frontend Integration
579
-
580
- Use `useCollectionPreview` in your frontend page components:
581
-
582
- ```tsx
583
- // src/routes/[slug].tsx
584
- import {
585
- PreviewField,
586
- PreviewProvider,
587
- useCollectionPreview,
588
- } from "@questpie/admin/client";
589
-
590
- function PageComponent({ initialData }) {
591
- const router = useRouter();
592
- const preview = useCollectionPreview({
593
- initialData,
594
- onRefresh: () => router.invalidate(),
595
- });
596
-
597
- return (
598
- <PreviewProvider
599
- isPreviewMode={preview.isPreviewMode}
600
- focusedField={preview.focusedField}
601
- onFieldClick={preview.handleFieldClick}
602
- >
603
- <PreviewField field="title" as="h1">
604
- {preview.data.title}
605
- </PreviewField>
606
- </PreviewProvider>
607
- );
608
- }
609
- ```
610
-
611
- #### Protocol
612
-
613
- The implemented preview messages are simple `postMessage` events:
614
-
615
- | Field | Description |
616
- | ----------------- | --------------------------------------- |
617
- | `PREVIEW_READY` | Preview iframe tells admin it is ready |
618
- | `PREVIEW_REFRESH` | Admin asks iframe to refresh data |
619
- | `FIELD_CLICKED` | Preview asks admin to focus a field |
620
- | `BLOCK_CLICKED` | Preview asks admin to select a block |
621
- | `FOCUS_FIELD` | Admin asks preview to highlight a field |
622
- | `SELECT_BLOCK` | Admin asks preview to highlight a block |
623
-
624
- ### Anti-Patterns (Preview)
625
-
626
- - **Using V2-only APIs in this template** — `useQuestpiePreview`, `PreviewRoot`, and `PreviewBlock` are not exported yet.
627
- - **Importing `app` inside previewed collection/block files** — use handler `ctx` values to avoid generated-app cycles.