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