@kardoe/quickback 0.5.13 → 0.5.15

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.js CHANGED
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import pc from "picocolors";
12
12
  // Version injected at build time by scripts/inject-version.ts
13
- const CLI_VERSION = "0.5.13";
13
+ const CLI_VERSION = "0.5.15";
14
14
  function getPackageVersion() {
15
15
  return CLI_VERSION;
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kardoe/quickback",
3
- "version": "0.5.13",
3
+ "version": "0.5.15",
4
4
  "description": "CLI for Quickback - one-shot backend generator",
5
5
  "author": "Paul Stenhouse",
6
6
  "license": "MIT",
@@ -4,26 +4,40 @@ description: Quickback API engine documentation - use when working with Quickbac
4
4
  allowed-tools: Read, Grep, Glob
5
5
  ---
6
6
 
7
- # Quickback: Backend Compiler for Secure APIs
7
+ # Quickback
8
8
 
9
- Quickback transforms declarative TypeScript definitions into secure, production-ready APIs. You define your database schema and security rules in a single file using Drizzle ORM — Quickback compiles them into a deployable backend with authentication, role-based permissions, tenant isolation, and field-level security.
9
+ Quickback is two things:
10
+
11
+ 1. **Compiler** — Transforms declarative TypeScript definitions into secure, production-ready APIs
12
+ 2. **Stack** — A Supabase alternative running entirely on Cloudflare (D1, R2, KV, Durable Objects, Queues, Workers AI)
10
13
 
11
14
  The output is standard TypeScript (Hono, Drizzle, Better Auth) running on your own infrastructure. Not a managed platform — real code you own and control.
12
15
 
13
- ## How It Works
16
+ ## Accessing Documentation
17
+
18
+ The fastest way to look up detailed docs is via the CLI:
19
+
20
+ ```bash
21
+ quickback docs # List all available topics
22
+ quickback docs <topic> # Show docs for a specific topic
23
+ quickback docs firewall # Example: firewall docs
24
+ quickback docs cms/record-layouts # Example: CMS record layouts
25
+ ```
26
+
27
+ Full online docs: https://docs.quickback.dev
28
+
29
+ ---
14
30
 
15
- 1. **Define** Schema + security rules in TypeScript using `defineTable()`
16
- 2. **Compile** — Quickback generates API routes, middleware, migrations, and RLS policies
17
- 3. **Deploy** — Standard tooling to Cloudflare Workers, Supabase, or Neon
31
+ # PART 1: THE COMPILER
18
32
 
19
- ## Architecture
33
+ The compiler takes your TypeScript definitions and generates API routes, middleware, migrations, typed SDKs, OpenAPI specs, and AI tool definitions.
20
34
 
21
35
  ```
22
36
  ┌─────────────────────────────────────────────────────────┐
23
37
  │ YOU DEFINE (in TypeScript) │
24
38
  │ • Drizzle schema (your data models) │
25
39
  │ • Security layers (Firewall, Access, Guards, Masking) │
26
- │ • Views (column-level projections)
40
+ │ • Views, Validation, Layouts
27
41
  │ • Actions (your business operations) │
28
42
  ├─────────────────────────────────────────────────────────┤
29
43
  │ QUICKBACK COMPILES TO │
@@ -35,24 +49,7 @@ The output is standard TypeScript (Hono, Drizzle, Better Auth) running on your o
35
49
  └─────────────────────────────────────────────────────────┘
36
50
  ```
37
51
 
38
- ## Four Security Layers
39
-
40
- Every API request passes through four layers in order:
41
-
42
- ```
43
- Request → Firewall → Access → Guards → Database → Masking → Response
44
- ```
45
-
46
- | Layer | Purpose | Failure |
47
- |-------|---------|---------|
48
- | **Firewall** | Tenant isolation via automatic WHERE clauses | 404 |
49
- | **Access** | Role-based CRUD permissions (deny by default) | 403 |
50
- | **Guards** | Field modification rules (protected/immutable fields) | 400 |
51
- | **Masking** | PII redaction for unauthorized viewers | — |
52
-
53
- ---
54
-
55
- # Project Structure
52
+ ## Project Structure
56
53
 
57
54
  ```
58
55
  my-app/
@@ -86,13 +83,9 @@ export default defineConfig({
86
83
 
87
84
  ## Compile Output and State Artifacts
88
85
 
89
- When a project has a `quickback/` folder and compiles runtime output to project root:
90
-
91
- - Runtime code stays in `build.outputDir` (for example `src/`, `wrangler.toml`, `package.json`).
92
- - Drizzle migration/state artifacts are written to `quickback/drizzle/...`.
93
- - Security contract report artifacts are written to `quickback/reports/...`.
94
-
95
- Treat `quickback/drizzle` as the canonical migration state location for repeated compiles.
86
+ - Runtime code stays in `build.outputDir` (e.g. `src/`, `wrangler.toml`, `package.json`)
87
+ - Drizzle migration/state artifacts are written to `quickback/drizzle/...`
88
+ - Security contract reports are written to `quickback/reports/...`
96
89
 
97
90
  ## Automatic Audit Fields
98
91
 
@@ -104,13 +97,13 @@ Quickback automatically injects these fields into every table:
104
97
 
105
98
  ---
106
99
 
107
- # Feature Definitions (Combined Mode)
100
+ ## Feature Definitions (Combined Mode)
108
101
 
109
102
  Features live in `quickback/features/{name}/` with one file per table using `defineTable()`.
110
103
 
111
104
  **Important**: Legacy mode (separate schema.ts + resource.ts) is no longer supported.
112
105
 
113
- ## Example: todos.ts
106
+ ### Example: todos.ts
114
107
 
115
108
  ```typescript
116
109
  import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
@@ -127,10 +120,9 @@ export const todos = sqliteTable("todos", {
127
120
 
128
121
  export default defineTable(todos, {
129
122
  firewall: {
130
- organization: {}, // Auto-detects 'organizationId' column
131
- owner: {}, // Auto-detects 'userId' column
123
+ organization: {},
124
+ owner: {},
132
125
  },
133
-
134
126
  crud: {
135
127
  list: { access: { roles: ["member", "admin"] } },
136
128
  get: { access: { roles: ["member", "admin"] } },
@@ -138,24 +130,29 @@ export default defineTable(todos, {
138
130
  update: { access: { roles: ["admin"] } },
139
131
  delete: { access: { roles: ["admin"] }, mode: "soft" },
140
132
  },
141
-
142
133
  guards: {
143
134
  createable: ["title", "description", "completed"],
144
135
  updatable: ["title", "description", "completed"],
145
136
  },
146
-
147
137
  masking: {
148
138
  userId: { type: "redact", show: { roles: ["admin"] } },
149
139
  },
140
+ layouts: {
141
+ default: {
142
+ sections: [
143
+ { label: "Details", columns: 2, fields: ["title", "completed"] },
144
+ { label: "Audit", collapsed: true, fields: ["userId"] },
145
+ ],
146
+ },
147
+ },
150
148
  });
151
149
  ```
152
150
 
153
- ## Internal/Junction Tables (No API)
151
+ ### Internal/Junction Tables (No API)
154
152
 
155
153
  Tables without a `defineTable()` default export get no API routes:
156
154
 
157
155
  ```typescript
158
- // No default export = no API routes generated
159
156
  export const roomAmenities = sqliteTable('room_amenities', {
160
157
  roomId: text('room_id').notNull(),
161
158
  amenityId: text('amenity_id').notNull(),
@@ -164,9 +161,22 @@ export const roomAmenities = sqliteTable('room_amenities', {
164
161
 
165
162
  ---
166
163
 
167
- # Security Pillars
164
+ ## Four Security Layers
165
+
166
+ Every API request passes through four layers in order:
167
+
168
+ ```
169
+ Request → Firewall → Access → Guards → Database → Masking → Response
170
+ ```
171
+
172
+ | Layer | Purpose | Failure |
173
+ |-------|---------|---------|
174
+ | **Firewall** | Tenant isolation via automatic WHERE clauses | 404 |
175
+ | **Access** | Role-based CRUD permissions (deny by default) | 403 |
176
+ | **Guards** | Field modification rules (protected/immutable fields) | 400 |
177
+ | **Masking** | PII redaction for unauthorized viewers | — |
168
178
 
169
- ## 1. Firewall — Data Isolation
179
+ ### 1. Firewall — Data Isolation
170
180
 
171
181
  Compiles WHERE clauses to isolate data by ownership. Auto-detects column names.
172
182
 
@@ -180,32 +190,25 @@ firewall: {
180
190
  }
181
191
  ```
182
192
 
183
- ### Auto-Detection
184
-
185
- Quickback finds columns by convention:
193
+ Auto-detection:
186
194
  - `organization` → looks for `organizationId` or `organization_id`
187
195
  - `owner` → looks for `userId` or `user_id`
188
196
  - `team` → looks for `teamId` or `team_id`
189
197
 
190
- ### Column Overrides
198
+ Column overrides:
191
199
 
192
200
  ```typescript
193
201
  firewall: {
194
202
  organization: {
195
- column: 'tenant_id', // Instead of 'organizationId'
196
- source: 'ctx.tenant.id', // Instead of 'ctx.activeOrgId'
203
+ column: 'tenant_id',
204
+ source: 'ctx.tenant.id',
197
205
  },
198
206
  }
199
207
  ```
200
208
 
201
- ### Owner Modes
202
-
203
- | Mode | Behavior |
204
- |------|----------|
205
- | (default) | Strict — only own records |
206
- | `optional` | Own records + records with NULL owner (admin pattern) |
209
+ Owner modes: default = strict (only own records), `optional` = own + NULL owner (admin pattern).
207
210
 
208
- ## 2. Access — Permission Checks
211
+ ### 2. Access — Permission Checks
209
212
 
210
213
  Role-based and record-based access control. Deny by default.
211
214
 
@@ -226,30 +229,11 @@ crud: {
226
229
  }
227
230
  ```
228
231
 
229
- ### Record Conditions
230
-
231
- | Operator | Example |
232
- |----------|---------|
233
- | `equals` | `{ status: { equals: 'active' } }` |
234
- | `notEquals` | `{ status: { notEquals: 'archived' } }` |
235
- | `in` | `{ status: { in: ['active', 'pending'] } }` |
236
- | `notIn` | `{ status: { notIn: ['deleted'] } }` |
237
- | `greaterThan` | `{ amount: { greaterThan: 0 } }` |
238
- | `lessThan` | `{ amount: { lessThan: 10000 } }` |
232
+ Record condition operators: `equals`, `notEquals`, `in`, `notIn`, `greaterThan`, `lessThan`
239
233
 
240
- ### Context Variables
234
+ Context variables: `$ctx.userId`, `$ctx.activeOrgId`, `$ctx.activeTeamId`, `$ctx.roles`, `$ctx.isAnonymous`
241
235
 
242
- | Variable | Type | Description |
243
- |----------|------|-------------|
244
- | `$ctx.userId` | string | Current user's ID |
245
- | `$ctx.activeOrgId` | string | Active organization ID |
246
- | `$ctx.activeTeamId` | string \| null | Active team ID |
247
- | `$ctx.roles` | string[] | User's roles in active org |
248
- | `$ctx.isAnonymous` | boolean | Anonymous user flag |
249
-
250
- ## 3. Guards — Field Protection
251
-
252
- Controls which fields can be modified.
236
+ ### 3. Guards Field Protection
253
237
 
254
238
  ```typescript
255
239
  guards: {
@@ -260,130 +244,84 @@ guards: {
260
244
  }
261
245
  ```
262
246
 
263
- **Compile-time validation**:
264
- - Field can't be in both `createable` and `protected`
265
- - Field can't be in both `updatable` and `immutable`
266
- - All referenced fields must exist in the schema
267
-
268
- **System-managed fields** (always protected):
269
- - `createdAt`, `createdBy` — Set on INSERT
270
- - `modifiedAt`, `modifiedBy` — Set on INSERT/UPDATE
271
- - `deletedAt`, `deletedBy` — Set on soft DELETE
247
+ System-managed fields (always protected): `createdAt`, `createdBy`, `modifiedAt`, `modifiedBy`, `deletedAt`, `deletedBy`
272
248
 
273
- ### PUT / Upsert
249
+ PUT/Upsert requires both `generateId: false` and `guards: false`.
274
250
 
275
- PUT is only available when BOTH conditions are met:
276
- - `generateId: false` in database config
277
- - `guards: false` (disables field protection)
278
-
279
- ```typescript
280
- export default defineTable(external_orders, {
281
- guards: false,
282
- crud: {
283
- put: { access: { roles: ['sync-service'] } },
284
- get: {},
285
- list: {},
286
- },
287
- });
288
- ```
289
-
290
- ## 4. Masking — PII Redaction
251
+ ### 4. Masking PII Redaction
291
252
 
292
253
  ```typescript
293
254
  masking: {
294
- ssn: {
295
- type: 'ssn', // *****6789
296
- show: { roles: ['admin', 'hr'] },
297
- },
298
- email: {
299
- type: 'email', // p***@e******.com
300
- show: { roles: ['admin'], or: 'owner' },
301
- },
255
+ ssn: { type: 'ssn', show: { roles: ['admin', 'hr'] } },
256
+ email: { type: 'email', show: { roles: ['admin'], or: 'owner' } },
302
257
  }
303
258
  ```
304
259
 
305
- ### Mask Types
306
-
307
- | Type | Output |
308
- |------|--------|
309
- | `email` | `p***@e******.com` |
310
- | `phone` | `******4567` |
311
- | `ssn` | `*****6789` |
312
- | `creditCard` | `************1234` |
313
- | `name` | `J*** D**` |
314
- | `redact` | `[REDACTED]` |
315
- | `custom` | Your function |
260
+ Mask types: `email`, `phone`, `ssn`, `creditCard`, `name`, `redact`, `custom`
316
261
 
317
- ### Auto-Detection
318
-
319
- The compiler warns if sensitive columns aren't explicitly configured:
320
-
321
- | Column Pattern | Default Mask |
322
- |---------------|-------------|
323
- | `email` | `email` |
324
- | `phone`, `mobile`, `fax` | `phone` |
325
- | `ssn`, `socialsecurity` | `ssn` |
326
- | `creditcard`, `cc` | `creditCard` |
327
- | `password`, `secret`, `token` | `redact` |
262
+ Auto-detection warns on unmasked sensitive columns (`email`, `phone`, `ssn`, `password`, etc.).
328
263
 
329
264
  ---
330
265
 
331
- # Views — Column-Level Security
266
+ ## Views — Column-Level Security
332
267
 
333
- Views are named projections that control which fields are visible based on role.
268
+ Named projections that control which fields are visible based on role.
334
269
 
335
270
  ```typescript
336
- export default defineTable(customers, {
337
- // ... firewall, guards, etc.
338
-
339
- views: {
340
- summary: {
341
- fields: ['id', 'name', 'email'],
342
- access: { roles: ['member', 'admin'] },
343
- },
344
- full: {
345
- fields: ['id', 'name', 'email', 'phone', 'ssn', 'address'],
346
- access: { roles: ['admin'] },
347
- },
271
+ views: {
272
+ summary: {
273
+ fields: ['id', 'name', 'email'],
274
+ access: { roles: ['member', 'admin'] },
348
275
  },
349
- });
276
+ full: {
277
+ fields: ['id', 'name', 'email', 'phone', 'ssn', 'address'],
278
+ access: { roles: ['admin'] },
279
+ },
280
+ }
350
281
  ```
351
282
 
352
- **Generated endpoints**:
353
- - `GET /api/v1/customers/views/summary` — returns only id, name, email
354
- - `GET /api/v1/customers/views/full` — returns all fields (admin only)
283
+ Generated endpoints: `GET /api/v1/{resource}/views/{viewName}`
284
+
285
+ ---
355
286
 
356
- Views support the same query parameters as list (filtering, sorting, pagination). Masking still applies to returned fields.
287
+ ## Validation
288
+
289
+ ```typescript
290
+ validation: {
291
+ name: { minLength: 1, maxLength: 100 },
292
+ capacity: { min: 1, max: 1000 },
293
+ roomType: { enum: ['meeting', 'conference', 'breakout'] },
294
+ email: { email: true },
295
+ code: { pattern: '^[A-Z]{3}$' },
296
+ }
297
+ ```
357
298
 
358
299
  ---
359
300
 
360
- # Validation
301
+ ## CMS Record Layouts
361
302
 
362
- Field-level validation rules compiled into the API:
303
+ Control how fields are grouped on the CMS record detail page.
363
304
 
364
305
  ```typescript
365
- export default defineTable(rooms, {
366
- // ... other config
367
-
368
- validation: {
369
- name: { minLength: 1, maxLength: 100 },
370
- capacity: { min: 1, max: 1000 },
371
- roomType: { enum: ['meeting', 'conference', 'breakout'] },
372
- email: { email: true },
373
- website: { url: true },
374
- code: { pattern: '^[A-Z]{3}$' },
306
+ layouts: {
307
+ default: {
308
+ sections: [
309
+ { label: "Contact Info", columns: 2, fields: ["name", "email", "phone"] },
310
+ { label: "Notes", collapsed: true, fields: ["notes", "internalNotes"] },
311
+ ],
375
312
  },
376
- });
313
+ }
377
314
  ```
378
315
 
316
+ Section options: `label` (string), `fields` (string[]), `columns` (1|2, default 1), `collapsed` (boolean, default false). Unassigned fields go to "Other Fields".
317
+
379
318
  ---
380
319
 
381
- # Actions — Custom Business Logic
320
+ ## Actions — Custom Business Logic
382
321
 
383
- Actions are custom API endpoints for business logic beyond CRUD. Defined in a separate `actions.ts` file using `defineActions()`.
322
+ Defined in a separate `actions.ts` file using `defineActions()`.
384
323
 
385
324
  ```typescript
386
- // quickback/features/todos/actions.ts
387
325
  import { todos } from './todos';
388
326
  import { defineActions } from '@quickback/compiler';
389
327
  import { z } from 'zod';
@@ -391,73 +329,33 @@ import { z } from 'zod';
391
329
  export default defineActions(todos, {
392
330
  complete: {
393
331
  description: "Mark todo as complete",
394
- input: z.object({
395
- completedAt: z.string().datetime().optional(),
396
- }),
397
- guard: {
398
- roles: ["member", "admin"],
399
- record: { completed: { equals: false } },
400
- },
332
+ input: z.object({ completedAt: z.string().datetime().optional() }),
333
+ guard: { roles: ["member", "admin"], record: { completed: { equals: false } } },
401
334
  execute: async ({ db, record, ctx, input }) => {
402
- // Inline handler
403
335
  await db.update(todos).set({ completed: true }).where(eq(todos.id, record.id));
404
336
  return { success: true };
405
337
  },
406
338
  sideEffects: "sync",
407
339
  },
408
-
409
340
  archive: {
410
341
  description: "Archive a todo",
411
342
  input: z.object({}),
412
343
  guard: { roles: ["admin"] },
413
- handler: "./handlers/archive", // OR: external file handler
344
+ handler: "./handlers/archive",
414
345
  },
415
346
  });
416
347
  ```
417
348
 
418
- **Generated Route**: `POST /api/v1/todos/:id/complete`
419
-
420
- ### Record-based vs Standalone Actions
421
-
422
- **Record-based** (default) — operates on a specific record via `:id`:
423
- ```typescript
424
- approve: {
425
- description: "Approve an invoice",
426
- input: z.object({ notes: z.string().optional() }),
427
- guard: { roles: ["admin"] },
428
- handler: "./handlers/approve",
429
- }
430
- // → POST /api/v1/invoices/:id/approve
431
- ```
432
-
433
- **Standalone** — custom endpoint not tied to a record:
434
- ```typescript
435
- chat: {
436
- standalone: true,
437
- path: "/chat",
438
- method: "POST",
439
- responseType: "stream",
440
- input: z.object({ message: z.string() }),
441
- guard: { roles: ["member"] },
442
- handler: "./handlers/chat",
443
- }
444
- // → POST /api/v1/todos/chat
445
- ```
446
-
447
- ### Action Options
349
+ **Record-based** (default): `POST /api/v1/{resource}/:id/{action}`
350
+ **Standalone**: `standalone: true`, custom `path` and `method`
448
351
 
449
- | Option | Values | Description |
450
- |--------|--------|-------------|
451
- | `standalone` | `true` | Not tied to a record |
452
- | `method` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` | HTTP method (default: POST) |
453
- | `responseType` | `json`, `stream`, `file` | Response format |
454
- | `sideEffects` | `sync`, `async`, `fire-and-forget` | Execution hint |
352
+ Action options: `standalone`, `method` (GET/POST/PUT/PATCH/DELETE), `responseType` (json/stream/file), `sideEffects` (sync/async/fire-and-forget)
455
353
 
456
354
  ---
457
355
 
458
- # API Reference
356
+ ## API Reference
459
357
 
460
- ## CRUD Operations
358
+ ### CRUD Operations
461
359
 
462
360
  | Method | Endpoint | Description |
463
361
  |--------|----------|-------------|
@@ -468,276 +366,266 @@ chat: {
468
366
  | `DELETE` | `/api/v1/{resource}/:id` | Delete record |
469
367
  | `PUT` | `/api/v1/{resource}/:id` | Upsert (if enabled) |
470
368
 
471
- ## Batch Operations
369
+ ### Batch Operations
472
370
 
473
- | Method | Endpoint | Description |
474
- |--------|----------|-------------|
475
- | `POST` | `/api/v1/{resource}/batch` | Batch create |
476
- | `PATCH` | `/api/v1/{resource}/batch` | Batch update |
477
- | `DELETE` | `/api/v1/{resource}/batch` | Batch delete |
478
- | `PUT` | `/api/v1/{resource}/batch` | Batch upsert (if enabled) |
479
-
480
- ```json
481
- // Request
482
- { "records": [{ "title": "A" }, { "title": "B" }], "options": { "atomic": false } }
483
-
484
- // Response
485
- { "success": [/* ... */], "errors": [/* ... */], "meta": { "total": 2, "succeeded": 2, "failed": 0 } }
486
- ```
487
-
488
- ## Query Parameters
371
+ `POST|PATCH|DELETE|PUT /api/v1/{resource}/batch` with `{ "records": [...], "options": { "atomic": false } }`
489
372
 
490
- ### Pagination
373
+ ### Query Parameters
491
374
 
492
- | Param | Default | Max |
493
- |-------|---------|-----|
494
- | `limit` | 50 | 100 |
495
- | `offset` | 0 | |
375
+ | Feature | Syntax |
376
+ |---------|--------|
377
+ | Pagination | `?limit=50&offset=0` (max 100) |
378
+ | Filter | `?status=active`, `?amount.gt=100`, `?status.in=draft,pending` |
379
+ | Sort | `?sort=status,-createdAt` (multi-sort, `-` = desc) |
380
+ | Fields | `?fields=id,name,status` |
381
+ | Total count | `?total=true` |
382
+ | Search | `?search=conference` (OR'd LIKE across text columns) |
496
383
 
497
- ### Filtering Operators
384
+ Filter operators: `.gt`, `.gte`, `.lt`, `.lte`, `.ne`, `.like`, `.in`
498
385
 
499
- | Operator | Example | SQL |
500
- |----------|---------|-----|
501
- | (none) | `?status=active` | `status = 'active'` |
502
- | `.gt` | `?amount.gt=100` | `amount > 100` |
503
- | `.gte` | `?amount.gte=100` | `amount >= 100` |
504
- | `.lt` | `?amount.lt=1000` | `amount < 1000` |
505
- | `.lte` | `?amount.lte=1000` | `amount <= 1000` |
506
- | `.ne` | `?status.ne=cancelled` | `status != 'cancelled'` |
507
- | `.like` | `?title.like=urgent` | `title LIKE '%urgent%'` |
508
- | `.in` | `?status.in=draft,pending` | `status IN ('draft','pending')` |
386
+ ### Response Format
509
387
 
510
- ### Sorting (Multi-Sort)
511
-
512
- ```
513
- ?sort=status,-createdAt # Multi-sort: status asc, createdAt desc
514
- ?sort=-createdAt # Single field descending
515
- ?sort=createdAt&order=desc # Legacy format (still supported)
388
+ ```json
389
+ {
390
+ "data": [{ "id": "...", "title": "Todo 1" }],
391
+ "pagination": { "limit": 10, "offset": 0, "count": 2, "total": 42 }
392
+ }
516
393
  ```
517
394
 
518
- No prefix = ascending, `-` prefix = descending. When commas or `-` detected, `order` param is ignored.
395
+ ### Error Responses
519
396
 
520
- ### Field Selection
397
+ | Status | Layer | Meaning |
398
+ |--------|-------|---------|
399
+ | `401` | Auth | Invalid/expired session |
400
+ | `403` | Access | Insufficient permissions |
401
+ | `404` | Firewall | Record not found or outside scope |
402
+ | `400` | Guards | Invalid field modification |
521
403
 
522
- ```
523
- ?fields=id,name,status # Return only these columns (LIST + GET routes)
524
- ```
404
+ ---
525
405
 
526
- Invalid field names silently ignored. Falls back to all columns if none valid. Views define their own fields — `?fields` doesn't apply to view routes. Masking still applies to selected fields.
406
+ ## Database Dialects
527
407
 
528
- ### Total Count
408
+ | Stack | Import | Table Function |
409
+ |-------|--------|----------------|
410
+ | Cloudflare D1 / SQLite | `drizzle-orm/sqlite-core` | `sqliteTable` |
411
+ | Supabase / PostgreSQL | `drizzle-orm/pg-core` | `pgTable` |
412
+ | MySQL | `drizzle-orm/mysql-core` | `mysqlTable` |
529
413
 
530
- ```
531
- ?total=true # Include pagination.total (LIST + VIEW routes)
532
- ```
414
+ ---
533
415
 
534
- Opt-in extra `COUNT(*)` query. Returns total matching records across all pages.
416
+ # PART 2: THE QUICKBACK STACK
535
417
 
536
- ### Search
418
+ The Quickback Stack is a production-ready backend platform built entirely on Cloudflare's edge infrastructure. It's a Supabase alternative where everything runs on your own Cloudflare account — your data, your infrastructure, global edge performance.
537
419
 
538
420
  ```
539
- ?search=conference # Full-text search across text columns (LIST + VIEW routes)
421
+ ┌─────────────────────────────────────────────────────────┐
422
+ │ QUICKBACK STACK ON CLOUDFLARE │
423
+ │ │
424
+ │ Workers — API runtime (Hono) │
425
+ │ D1 — SQLite database at the edge │
426
+ │ R2 — S3-compatible file storage │
427
+ │ KV — Distributed key-value store │
428
+ │ Durable Objects — Realtime WebSockets │
429
+ │ Queues — Background job processing │
430
+ │ Workers AI — Embeddings & vector search │
431
+ │ Better Auth — Authentication & organizations │
432
+ └─────────────────────────────────────────────────────────┘
540
433
  ```
541
434
 
542
- OR'd LIKE across all `text()` schema columns (system columns excluded). Combine with filters: `?search=urgent&status=active`.
435
+ ## Authentication (Better Auth)
543
436
 
544
- ## Response Format
437
+ Built on Better Auth with multi-tenant organization support.
545
438
 
546
- ```json
547
- {
548
- "data": [{ "id": "...", "title": "Todo 1" }],
549
- "pagination": {
550
- "limit": 10,
551
- "offset": 0,
552
- "count": 2,
553
- "total": 42
554
- }
439
+ - Email/password, magic links, passkeys, email OTP
440
+ - Three org roles: `owner`, `admin`, `member`
441
+ - Session storage in KV namespace
442
+ - All auth routes at `/auth/v1/*`
443
+ - Extensible via Better Auth plugins
444
+
445
+ ```typescript
446
+ // Config
447
+ providers: {
448
+ auth: defineAuth("better-auth"),
555
449
  }
556
450
  ```
557
451
 
558
- `count` = records on this page. `total` = total matching records (only when `?total=true`).
452
+ Docs: `quickback docs stack/auth/using-auth` | https://docs.quickback.dev/stack/auth
559
453
 
560
- ---
454
+ ## Database (D1)
455
+
456
+ SQLite at the edge with zero configuration. Multi-database pattern for independent scaling:
561
457
 
562
- # Webhooks
458
+ | Binding | Purpose |
459
+ |---------|---------|
460
+ | `DB` | Application data (features) |
461
+ | `AUTH_DB` | Auth sessions & users |
462
+ | `FILES_DB` | File metadata |
463
+ | `WEBHOOKS_DB` | Webhook tracking |
563
464
 
564
- ## Configuration
465
+ - Drizzle ORM for type-safe queries
466
+ - Auto-generated migrations on compile
467
+ - Application-layer security (firewall, access, guards, masking)
468
+ - Local dev with `.wrangler/state/`
469
+ - Neon Postgres available as alternative
565
470
 
566
471
  ```typescript
567
- // quickback.config.ts
568
472
  providers: {
569
473
  database: defineDatabase("cloudflare-d1", {
570
474
  splitDatabases: true,
571
- webhooksBinding: "WEBHOOKS_DB",
572
475
  }),
573
476
  }
574
477
  ```
575
478
 
576
- ## Inbound Webhooks (Receiving)
479
+ Docs: `quickback docs stack/database/d1` | https://docs.quickback.dev/stack/database/d1
577
480
 
578
- ```typescript
579
- import { onWebhookEvent } from './lib/webhooks';
481
+ ## File Storage (R2)
580
482
 
581
- onWebhookEvent('stripe:checkout.session.completed', async (ctx) => {
582
- const { data, env } = ctx;
583
- await createSubscription({ ... });
584
- });
585
- ```
483
+ S3-compatible object storage with built-in access control.
586
484
 
587
- ## Outbound Webhooks (Sending)
485
+ - Two-worker architecture: API worker (upload/manage) + Files worker (serve)
486
+ - Bucket-scoped access policies (public, organization, user)
487
+ - File metadata tracked in `FILES_DB`
488
+ - Soft deletes with org-level tenant isolation
489
+ - API at `/storage/v1/*`
588
490
 
589
- ```typescript
590
- import { emitWebhookEvent } from './lib/webhooks';
491
+ Docs: `quickback docs stack/storage/r2` | https://docs.quickback.dev/stack/storage/r2
591
492
 
592
- await emitWebhookEvent(
593
- 'user.created',
594
- { id: user.id, email: user.email },
595
- { organizationId: orgId },
596
- env
597
- );
598
- ```
493
+ ## KV Storage
599
494
 
600
- ## Available Events
495
+ Distributed key-value store optimized for reads (300+ edge locations, sub-millisecond).
601
496
 
602
- | Event | Description |
603
- |-------|-------------|
604
- | `user.created/updated/deleted` | User lifecycle |
605
- | `subscription.created/updated/cancelled/renewed` | Subscription lifecycle |
606
- | `organization.created/updated/deleted` | Organization lifecycle |
607
- | `organization.member_added/removed` | Membership changes |
608
- | `file.uploaded/deleted` | File storage |
497
+ - Use cases: sessions, caching, rate limiting, feature flags
498
+ - Eventually consistent (60 second propagation)
499
+ - TTL/expiration support
609
500
 
610
- **Wildcards**: `user.*`, `subscription.*`, `organization.*`, `file.*`, `*`
501
+ Docs: `quickback docs stack/storage/kv` | https://docs.quickback.dev/stack/storage/kv
611
502
 
612
- ---
503
+ ## Realtime (Durable Objects)
613
504
 
614
- # CLI Commands
505
+ WebSocket connections for live updates via organization-scoped Durable Objects.
615
506
 
616
- ## Core Commands
507
+ - CRUD event broadcasting (insert, update, delete)
508
+ - Custom broadcasts and event namespaces
509
+ - Role-based filtering and per-role field masking
510
+ - Session token or API key authentication
511
+ - Type-safe with `defineRealtime()` for custom events
512
+ - Endpoint: `/realtime/v1/websocket`
617
513
 
618
- | Command | Description |
619
- |---------|-------------|
620
- | `quickback create <template> <name>` | Create project from template |
621
- | `quickback compile` | Compile definitions to output |
622
- | `quickback login` | Authenticate for Pro templates |
623
- | `quickback logout` | Clear stored credentials |
624
- | `quickback whoami` | Show current auth status |
514
+ Docs: `quickback docs stack/realtime/durable-objects` | https://docs.quickback.dev/stack/realtime
625
515
 
626
- ## Available Templates
516
+ ## Queues (Background Processing)
627
517
 
628
- | Template | Stack | Status |
629
- |----------|-------|--------|
630
- | `cloudflare` | Cloudflare Workers + D1 + Better Auth | Free |
631
- | `bun` | Bun + SQLite + Better Auth | Free |
632
- | `turso` | Turso/LibSQL + Better Auth | Pro |
518
+ Cloudflare Queues for reliable async job processing.
633
519
 
634
- ## Claude Code Integration
520
+ | Queue | Purpose |
521
+ |-------|---------|
522
+ | `EMBEDDINGS_QUEUE` | Auto-generate embeddings |
523
+ | `WEBHOOKS_QUEUE` | Webhook delivery |
524
+ | Custom queues | Your background jobs |
635
525
 
636
- | Command | Description |
637
- |---------|-------------|
638
- | `quickback claude install` | Interactive install of Claude Code skill |
639
- | `quickback claude install --global` | Install globally |
640
- | `quickback claude install --local` | Install for current project |
641
- | `quickback claude update` | Update to latest skill version |
642
- | `quickback claude remove` | Remove the skill |
643
- | `quickback claude status` | Show install status |
526
+ - Custom handlers via `defineQueue()` in `services/queues/`
527
+ - Auto-retry up to 3 times, max batch 10, 30s timeout
528
+ - Chaining between queues
644
529
 
645
- ---
530
+ Docs: `quickback docs stack/queues/using-queues` | https://docs.quickback.dev/stack/queues
646
531
 
647
- # Development Workflow
532
+ ## Vector & Embeddings (Workers AI)
648
533
 
649
- ```bash
650
- # 1. Create project
651
- quickback create cloudflare my-app
534
+ Auto-generated embeddings for similarity search and classification.
652
535
 
653
- # 2. Define features in quickback/features/
536
+ - Table-level config via `embeddings` in `defineTable()`
537
+ - Service-level config via `defineEmbedding()`
538
+ - Default model: `@cf/baai/bge-base-en-v1.5` (768 dimensions)
539
+ - Async processing via `EMBEDDINGS_QUEUE`
540
+ - Vector storage in D1 + optional Vectorize index
541
+ - API: `/api/v1/embeddings`
654
542
 
655
- # 3. Compile
656
- quickback compile
543
+ Docs: `quickback docs stack/vector/embeddings` | https://docs.quickback.dev/stack/vector
657
544
 
658
- # 4. Run
659
- cd dist
660
- npm install
661
- npm run db:generate
662
- npm run dev
663
- ```
664
-
665
- ---
545
+ ## Webhooks
666
546
 
667
- # Deployment Targets
547
+ ### Inbound (Receiving)
668
548
 
669
- ## Cloudflare Stack (Full Edge)
670
-
671
- Hono API on Workers, D1 database, Better Auth, R2 file storage, KV, Queues, Durable Objects for realtime.
549
+ Receive events from Stripe, Paddle, GitHub, etc. at `POST /webhooks/v1/inbound/:provider`
672
550
 
673
551
  ```typescript
674
- defineConfig({
675
- providers: {
676
- runtime: defineRuntime("cloudflare"),
677
- database: defineDatabase("cloudflare-d1"),
678
- auth: defineAuth("better-auth"),
679
- },
552
+ import { onWebhookEvent } from './lib/webhooks';
553
+
554
+ onWebhookEvent('stripe:checkout.session.completed', async (ctx) => {
555
+ const { data, env } = ctx;
556
+ await createSubscription({ ... });
680
557
  });
681
558
  ```
682
559
 
683
- ## Supabase (RLS Policies)
560
+ ### Outbound (Sending)
684
561
 
685
- Compiles Quickback definitions into Row Level Security policies for Postgres-level security.
562
+ Emit signed events when data changes. HMAC-SHA256 signing, async delivery via queue with exponential backoff retry.
686
563
 
687
564
  ```typescript
688
- defineConfig({
689
- providers: {
690
- runtime: defineRuntime("supabase"),
691
- database: defineDatabase("supabase"),
692
- auth: defineAuth("supabase"),
693
- },
694
- });
565
+ import { emitWebhookEvent } from './lib/webhooks';
566
+
567
+ await emitWebhookEvent('user.created', { id: user.id, email: user.email }, { organizationId: orgId }, env);
695
568
  ```
696
569
 
697
- ## Neon (Serverless Postgres)
570
+ Event patterns: `user.*`, `subscription.*`, `organization.*`, `file.*`, `*`
571
+ Endpoint management: `/webhooks/v1/endpoints`
698
572
 
699
- Serverless Postgres with compiled RLS policies and branching support.
573
+ Docs: `quickback docs stack/webhooks/outbound` | https://docs.quickback.dev/stack/webhooks
700
574
 
701
575
  ---
702
576
 
703
- # Error Responses
577
+ # CLI Commands
704
578
 
705
- | Status | Layer | Meaning |
706
- |--------|-------|---------|
707
- | `401` | Auth | Invalid/expired session |
708
- | `403` | Access | Insufficient permissions |
709
- | `404` | Firewall | Record not found or outside scope |
710
- | `400` | Guards | Invalid field modification |
711
- | `429` | Rate limit | Too many requests |
579
+ | Command | Description |
580
+ |---------|-------------|
581
+ | `quickback create <template> <name>` | Create project from template |
582
+ | `quickback compile` | Compile definitions to output |
583
+ | `quickback docs [topic]` | Browse built-in documentation |
584
+ | `quickback login` | Authenticate for Pro templates |
585
+ | `quickback logout` | Clear stored credentials |
586
+ | `quickback whoami` | Show current auth status |
587
+ | `quickback claude install` | Install Claude Code skill |
588
+ | `quickback claude update` | Update to latest skill version |
712
589
 
713
- ---
590
+ ## Available Templates
714
591
 
715
- # Database Dialects
592
+ | Template | Stack | Status |
593
+ |----------|-------|--------|
594
+ | `cloudflare` | Cloudflare Workers + D1 + Better Auth | Free |
595
+ | `bun` | Bun + SQLite + Better Auth | Free |
596
+ | `turso` | Turso/LibSQL + Better Auth | Pro |
716
597
 
717
- Detect from `quickback.config.ts` and use the correct imports:
598
+ ## Development Workflow
718
599
 
719
- | Stack | Import | Table Function |
720
- |-------|--------|----------------|
721
- | Cloudflare D1 / SQLite | `drizzle-orm/sqlite-core` | `sqliteTable` |
722
- | Supabase / PostgreSQL | `drizzle-orm/pg-core` | `pgTable` |
723
- | MySQL | `drizzle-orm/mysql-core` | `mysqlTable` |
600
+ ```bash
601
+ quickback create cloudflare my-app # 1. Create project
602
+ # Define features in quickback/features/
603
+ quickback compile # 2. Compile
604
+ cd dist && npm install && npm run dev # 3. Run
605
+ ```
724
606
 
725
607
  ---
726
608
 
727
- # Documentation
728
-
729
- Full documentation at https://docs.quickback.dev
730
-
731
- - [Quick Start](https://docs.quickback.dev/definitions/quick-start)
732
- - [Concepts](https://docs.quickback.dev/definitions/concepts)
733
- - [Database Schema](https://docs.quickback.dev/definitions/database-schema)
734
- - [CRUD Endpoints](https://docs.quickback.dev/definitions/crud-endpoints)
735
- - [Views](https://docs.quickback.dev/definitions/views)
736
- - [Actions](https://docs.quickback.dev/definitions/actions)
737
- - [Firewall](https://docs.quickback.dev/definitions/firewall)
738
- - [Access](https://docs.quickback.dev/definitions/access)
739
- - [Guards](https://docs.quickback.dev/definitions/guards)
740
- - [Masking](https://docs.quickback.dev/definitions/masking)
741
- - [CLI Reference](https://docs.quickback.dev/compiler/cli)
742
- - [Cloudflare Stack](https://docs.quickback.dev/stack/cloudflare)
743
- - [Quick Reference](https://docs.quickback.dev/stack/reference)
609
+ # Online Documentation
610
+
611
+ - [Getting Started](https://docs.quickback.dev/compiler/getting-started)
612
+ - [Concepts](https://docs.quickback.dev/compiler/definitions/concepts)
613
+ - [Database Schema](https://docs.quickback.dev/compiler/definitions/schema)
614
+ - [Firewall](https://docs.quickback.dev/compiler/definitions/firewall)
615
+ - [Access](https://docs.quickback.dev/compiler/definitions/access)
616
+ - [Guards](https://docs.quickback.dev/compiler/definitions/guards)
617
+ - [Masking](https://docs.quickback.dev/compiler/definitions/masking)
618
+ - [Views](https://docs.quickback.dev/compiler/definitions/views)
619
+ - [Actions](https://docs.quickback.dev/compiler/definitions/actions)
620
+ - [CRUD API](https://docs.quickback.dev/compiler/using-the-api/crud)
621
+ - [Query Parameters](https://docs.quickback.dev/compiler/using-the-api/query-params)
622
+ - [CLI Reference](https://docs.quickback.dev/compiler/cloud-compiler/cli)
623
+ - [Stack Overview](https://docs.quickback.dev/stack)
624
+ - [D1 Database](https://docs.quickback.dev/stack/database/d1)
625
+ - [R2 Storage](https://docs.quickback.dev/stack/storage/r2)
626
+ - [Realtime](https://docs.quickback.dev/stack/realtime)
627
+ - [Queues](https://docs.quickback.dev/stack/queues)
628
+ - [Embeddings](https://docs.quickback.dev/stack/vector)
629
+ - [Webhooks](https://docs.quickback.dev/stack/webhooks)
630
+ - [CMS Overview](https://docs.quickback.dev/cms)
631
+ - [CMS Record Layouts](https://docs.quickback.dev/cms/record-layouts)
@@ -19,6 +19,7 @@ You deeply understand:
19
19
  - **Actions**: Custom endpoints using `defineActions()` with Zod schemas
20
20
  - **Views**: Column-level security with named projections
21
21
  - **Validation**: Field-level validation rules
22
+ - **Layouts**: CMS record page field grouping with sections, columns, and collapsed state
22
23
 
23
24
  ## When Invoked
24
25
 
@@ -193,10 +194,24 @@ Before finishing, verify:
193
194
  - [ ] Masking for any PII fields
194
195
  - [ ] Views for different visibility levels (if needed)
195
196
  - [ ] Validation rules for constrained fields (if needed)
197
+ - [ ] Layouts for CMS record page field grouping (if needed)
196
198
  - [ ] No audit fields in schema (auto-injected)
197
199
  - [ ] Using `defineTable()` combined mode (not separate schema.ts + resource.ts)
198
200
  - [ ] Actions use `defineActions()` with Zod schemas (not JSON schema)
199
201
 
202
+ ## Accessing Documentation
203
+
204
+ When you need to look up Quickback docs, use the CLI — it bundles all docs offline:
205
+
206
+ ```bash
207
+ quickback docs # List all available topics
208
+ quickback docs <topic> # Show docs for a specific topic
209
+ quickback docs firewall # Example: firewall docs
210
+ quickback docs cms/record-layouts # Example: CMS record layouts
211
+ ```
212
+
213
+ Full online docs: https://docs.quickback.dev
214
+
200
215
  ## Response Style
201
216
 
202
217
  - Be direct and practical