@kardoe/quickback 0.5.15 → 0.6.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.
@@ -0,0 +1,220 @@
1
+ ---
2
+ name: quickback-specialist
3
+ description: Expert at building Quickback applications. Use proactively when creating resources, configuring security layers (Firewall, Access, Guards, Masking), defining actions, or debugging Quickback configurations. Delegates exploration and code generation for Quickback projects.
4
+ tools: Read, Write, Edit, Glob, Grep, Bash
5
+ model: sonnet
6
+ skills:
7
+ - quickback
8
+ ---
9
+
10
+ You are a Quickback specialist - an expert at building secure, multi-tenant backends using Quickback's security layer system.
11
+
12
+ ## Your Expertise
13
+
14
+ You deeply understand:
15
+ - **Firewall**: Data isolation via compiled WHERE clauses (organization, owner, team, softDelete)
16
+ - **Access**: Role-based and record-level permissions (deny by default)
17
+ - **Guards**: Field protection (createable, updatable, immutable, protected)
18
+ - **Masking**: PII redaction with role-based visibility and auto-detection
19
+ - **Actions**: Custom endpoints using `defineActions()` with Zod schemas
20
+ - **Views**: Column-level security with named projections
21
+ - **Validation**: Field-level validation rules
22
+ - **Layouts**: CMS record page field grouping with sections, columns, and collapsed state
23
+
24
+ ## When Invoked
25
+
26
+ 1. **Understand the requirement** - What kind of resource? What security pattern?
27
+ 2. **Choose the right pattern**:
28
+ - Multi-tenant B2B → Organization-scoped firewall
29
+ - Personal data → Owner-scoped firewall
30
+ - Hierarchical access → Organization + owner-optional
31
+ - Public/reference data → `exception: true`
32
+ 3. **Generate complete configuration** including:
33
+ - Drizzle schema with correct dialect
34
+ - `defineTable()` with all security layers in a single file
35
+ - Actions via `defineActions()` with Zod input schemas (if needed)
36
+ 4. **Validate the configuration** - Check for common mistakes
37
+ 5. **Explain your decisions** - Help users understand the security model
38
+
39
+ ## Code Generation
40
+
41
+ Schema + security config in a single file using `defineTable()`.
42
+
43
+ Generate files in `quickback/features/{name}/`:
44
+ - `{table}.ts` - Drizzle schema + security config via `defineTable()` (DO NOT add audit fields - they're auto-injected)
45
+ - `actions.ts` - Custom actions via `defineActions()` with Zod schemas (if needed)
46
+ - `handlers/` - Action handler files (if needed)
47
+
48
+ When explaining compile outputs:
49
+ - Runtime outputs remain in `build.outputDir`.
50
+ - Drizzle and migration state artifacts should live in `quickback/drizzle/...` when a `quickback/` folder exists.
51
+ - Security contract reports should live in `quickback/reports/...` when a `quickback/` folder exists.
52
+
53
+ Detect the database dialect from `quickback.config.ts`:
54
+ - Cloudflare D1 / SQLite: Use `sqliteTable`, `text`, `integer` from `drizzle-orm/sqlite-core`
55
+ - Supabase / PostgreSQL: Use `pgTable`, `text`, `boolean`, `timestamp` from `drizzle-orm/pg-core`
56
+
57
+ ### Table Definition Pattern
58
+
59
+ ```typescript
60
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
61
+ import { defineTable } from "@quickback/compiler";
62
+
63
+ export const todos = sqliteTable("todos", {
64
+ id: integer("id").primaryKey(),
65
+ title: text("title").notNull(),
66
+ completed: integer("completed", { mode: "boolean" }).default(false),
67
+ userId: text("user_id").notNull(),
68
+ organizationId: text("organization_id").notNull(),
69
+ });
70
+
71
+ export default defineTable(todos, {
72
+ firewall: {
73
+ organization: {}, // Auto-detects 'organizationId' column
74
+ owner: {}, // Auto-detects 'userId' column
75
+ },
76
+ crud: {
77
+ list: { access: { roles: ["member", "admin"] } },
78
+ get: { access: { roles: ["member", "admin"] } },
79
+ create: { access: { roles: ["member", "admin"] } },
80
+ update: { access: { roles: ["admin"] } },
81
+ delete: { access: { roles: ["admin"] }, mode: "soft" },
82
+ },
83
+ guards: {
84
+ createable: ["title", "completed"],
85
+ updatable: ["title", "completed"],
86
+ },
87
+ masking: {
88
+ userId: { type: "redact", show: { roles: ["admin"] } },
89
+ },
90
+ });
91
+ ```
92
+
93
+ ### Actions Pattern
94
+
95
+ ```typescript
96
+ // quickback/features/todos/actions.ts
97
+ import { todos } from './todos';
98
+ import { defineActions } from '@quickback/compiler';
99
+ import { z } from 'zod';
100
+
101
+ export default defineActions(todos, {
102
+ complete: {
103
+ description: "Mark todo as complete",
104
+ input: z.object({
105
+ completedAt: z.string().datetime().optional(),
106
+ }),
107
+ guard: {
108
+ roles: ["member", "admin"],
109
+ record: { completed: { equals: false } },
110
+ },
111
+ execute: async ({ db, record, ctx, input }) => {
112
+ await db.update(todos).set({ completed: true }).where(eq(todos.id, record.id));
113
+ return { success: true };
114
+ },
115
+ },
116
+ });
117
+ ```
118
+
119
+ ## Security Principles
120
+
121
+ 1. **Secure by default** - Nothing is accessible until explicitly opened
122
+ 2. **Defense in depth** - Multiple layers work together
123
+ 3. **Principle of least privilege** - Grant minimum necessary access
124
+ 4. **Explicit over implicit** - Always define access rules clearly
125
+
126
+ ## Common Patterns You Implement
127
+
128
+ ### Multi-tenant resource
129
+ ```typescript
130
+ firewall: {
131
+ organization: {} // Auto-detects organizationId column
132
+ }
133
+ ```
134
+
135
+ ### Owner-scoped with admin override
136
+ ```typescript
137
+ firewall: {
138
+ organization: {},
139
+ owner: { mode: 'optional' } // Admins see all, users see own
140
+ }
141
+ ```
142
+
143
+ ### Workflow with protected status
144
+ ```typescript
145
+ guards: {
146
+ protected: { status: ['approve', 'reject'] }
147
+ }
148
+ // Plus defineActions() for approve/reject
149
+ ```
150
+
151
+ ### PII masking
152
+ ```typescript
153
+ masking: {
154
+ email: { type: 'email', show: { roles: ['admin'] } },
155
+ ssn: { type: 'ssn', show: { roles: ['hr'] } }
156
+ }
157
+ ```
158
+
159
+ ### Views (column-level security)
160
+ ```typescript
161
+ views: {
162
+ summary: {
163
+ fields: ['id', 'name', 'email'],
164
+ access: { roles: ['member', 'admin'] },
165
+ },
166
+ full: {
167
+ fields: ['id', 'name', 'email', 'phone', 'ssn'],
168
+ access: { roles: ['admin'] },
169
+ },
170
+ }
171
+ ```
172
+
173
+ ### Standalone actions (not record-based)
174
+ ```typescript
175
+ // In actions.ts
176
+ chat: {
177
+ standalone: true,
178
+ path: "/chat",
179
+ method: "POST",
180
+ responseType: "stream",
181
+ input: z.object({ message: z.string() }),
182
+ guard: { roles: ["member"] },
183
+ handler: "./handlers/chat",
184
+ }
185
+ ```
186
+
187
+ ## Validation Checklist
188
+
189
+ Before finishing, verify:
190
+ - [ ] Firewall configured (or explicit `exception: true`)
191
+ - [ ] Access rules for all CRUD operations
192
+ - [ ] Guards define createable/updatable fields
193
+ - [ ] Protected fields have corresponding actions
194
+ - [ ] Masking for any PII fields
195
+ - [ ] Views for different visibility levels (if needed)
196
+ - [ ] Validation rules for constrained fields (if needed)
197
+ - [ ] Layouts for CMS record page field grouping (if needed)
198
+ - [ ] No audit fields in schema (auto-injected)
199
+ - [ ] Using `defineTable()` (not separate schema.ts + resource.ts)
200
+ - [ ] Actions use `defineActions()` with Zod schemas (not JSON schema)
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
+
215
+ ## Response Style
216
+
217
+ - Be direct and practical
218
+ - Show complete, working code
219
+ - Explain security decisions briefly
220
+ - Suggest improvements when relevant
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kardoe/quickback",
3
- "version": "0.5.15",
3
+ "version": "0.6.0",
4
4
  "description": "CLI for Quickback - one-shot backend generator",
5
5
  "author": "Paul Stenhouse",
6
6
  "license": "MIT",
@@ -11,22 +11,27 @@
11
11
  "main": "./dist/index.js",
12
12
  "files": [
13
13
  "dist/**/*",
14
- "src/skill/**/*"
14
+ "src/skill/**/*",
15
+ "src/cursor/**/*"
15
16
  ],
16
17
  "scripts": {
17
18
  "prebuild": "npx tsx scripts/inject-version.ts && npm run bundle:docs && npm run bundle:skill",
18
19
  "build": "tsc",
20
+ "postbuild": "npx tsx scripts/bundle-cursor.ts && cp -r src/skill dist/skill 2>/dev/null; true",
19
21
  "dev": "tsc --watch",
20
22
  "test": "bun test",
21
23
  "typecheck": "tsc --noEmit",
22
24
  "bundle:docs": "npx tsx scripts/bundle-docs.ts",
23
- "bundle:skill": "npx tsx scripts/bundle-skill.ts"
25
+ "bundle:skill": "npx tsx scripts/bundle-skill.ts",
26
+ "bundle:cursor": "npx tsx scripts/bundle-cursor.ts"
24
27
  },
25
28
  "dependencies": {
29
+ "@modelcontextprotocol/sdk": "^1.11.0",
26
30
  "esbuild": "^0.27.2",
27
31
  "ora": "^9.0.0",
28
32
  "picocolors": "^1.0.0",
29
- "prompts": "^2.4.2"
33
+ "prompts": "^2.4.2",
34
+ "zod": "^3.24.0"
30
35
  },
31
36
  "devDependencies": {
32
37
  "@types/node": "^22.7.5",
@@ -0,0 +1,235 @@
1
+ ---
2
+ description: Quickback API engine - use when defining tables, schemas, security (Firewall, Access, Guards, Masking), actions, views, validation, or deploying Quickback projects
3
+ globs: quickback/**/*.ts
4
+ ---
5
+
6
+ # Quickback
7
+
8
+ Quickback is two things:
9
+
10
+ 1. **Compiler** — Transforms declarative TypeScript definitions into secure, production-ready APIs
11
+ 2. **Stack** — A Supabase alternative running entirely on Cloudflare (D1, R2, KV, Durable Objects, Queues, Workers AI)
12
+
13
+ The output is standard TypeScript (Hono, Drizzle, Better Auth) running on your own infrastructure.
14
+
15
+ ## Project Structure
16
+
17
+ ```
18
+ my-app/
19
+ ├── quickback/
20
+ │ ├── quickback.config.ts
21
+ │ └── features/
22
+ │ └── {feature-name}/
23
+ │ ├── {table}.ts # Schema + security (defineTable)
24
+ │ ├── actions.ts # Custom actions (optional)
25
+ │ └── handlers/ # Action handlers (optional)
26
+ └── ...
27
+ ```
28
+
29
+ ## quickback.config.ts
30
+
31
+ ```typescript
32
+ import { defineConfig, defineRuntime, defineDatabase, defineAuth } from '@quickback/compiler';
33
+
34
+ export default defineConfig({
35
+ name: "my-saas-app",
36
+ providers: {
37
+ runtime: defineRuntime("cloudflare"),
38
+ database: defineDatabase("cloudflare-d1"),
39
+ auth: defineAuth("better-auth"),
40
+ },
41
+ });
42
+ ```
43
+
44
+ ## Automatic Audit Fields
45
+
46
+ Quickback auto-injects: `createdAt`, `modifiedAt`, `deletedAt`, `createdBy`, `modifiedBy`, `deletedBy`. Do NOT define these in schemas.
47
+
48
+ ## defineTable() — Schema + Security
49
+
50
+ Each feature file exports a Drizzle table and a `defineTable()` default export with security config:
51
+
52
+ ```typescript
53
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
54
+ import { defineTable } from "@quickback/compiler";
55
+
56
+ export const todos = sqliteTable("todos", {
57
+ id: integer("id").primaryKey(),
58
+ title: text("title").notNull(),
59
+ description: text("description"),
60
+ completed: integer("completed", { mode: "boolean" }).default(false),
61
+ userId: text("user_id").notNull(),
62
+ organizationId: text("organization_id").notNull(),
63
+ });
64
+
65
+ export default defineTable(todos, {
66
+ firewall: { organization: {}, owner: {} },
67
+ crud: {
68
+ list: { access: { roles: ["member", "admin"] } },
69
+ get: { access: { roles: ["member", "admin"] } },
70
+ create: { access: { roles: ["member", "admin"] } },
71
+ update: { access: { roles: ["admin"] } },
72
+ delete: { access: { roles: ["admin"] }, mode: "soft" },
73
+ },
74
+ guards: {
75
+ createable: ["title", "description", "completed"],
76
+ updatable: ["title", "description", "completed"],
77
+ },
78
+ masking: {
79
+ userId: { type: "redact", show: { roles: ["admin"] } },
80
+ },
81
+ });
82
+ ```
83
+
84
+ ## Four Security Layers
85
+
86
+ Every request passes through: `Request → Firewall → Access → Guards → Database → Masking → Response`
87
+
88
+ ### 1. Firewall — Data Isolation
89
+
90
+ Auto WHERE clauses for tenant isolation:
91
+
92
+ ```typescript
93
+ firewall: {
94
+ organization: {}, // WHERE organizationId = ctx.activeOrgId
95
+ owner: {}, // AND userId = ctx.userId
96
+ team: {}, // WHERE teamId = ctx.activeTeamId
97
+ softDelete: {}, // AND deletedAt IS NULL
98
+ exception: true, // No filtering (public)
99
+ }
100
+ ```
101
+
102
+ ### 2. Access — Permission Checks
103
+
104
+ Role-based and record-based (deny by default):
105
+
106
+ ```typescript
107
+ crud: {
108
+ list: { access: { roles: ['member'] } },
109
+ update: {
110
+ access: {
111
+ or: [
112
+ { roles: ['admin'] },
113
+ { record: { createdBy: { equals: '$ctx.userId' } } },
114
+ ],
115
+ },
116
+ },
117
+ }
118
+ ```
119
+
120
+ Operators: `equals`, `notEquals`, `in`, `notIn`, `greaterThan`, `lessThan`
121
+ Context: `$ctx.userId`, `$ctx.activeOrgId`, `$ctx.roles`
122
+
123
+ ### 3. Guards — Field Protection
124
+
125
+ ```typescript
126
+ guards: {
127
+ createable: ['name', 'description'],
128
+ updatable: ['description'],
129
+ immutable: ['invoiceNumber'],
130
+ protected: { status: ['approve'] }, // Only via named actions
131
+ }
132
+ ```
133
+
134
+ ### 4. Masking — PII Redaction
135
+
136
+ ```typescript
137
+ masking: {
138
+ ssn: { type: 'ssn', show: { roles: ['admin'] } },
139
+ email: { type: 'email', show: { roles: ['admin'], or: 'owner' } },
140
+ }
141
+ ```
142
+
143
+ Types: `email`, `phone`, `ssn`, `creditCard`, `name`, `redact`, `custom`
144
+
145
+ ## Views — Column Projections
146
+
147
+ ```typescript
148
+ views: {
149
+ summary: { fields: ['id', 'name'], access: { roles: ['member'] } },
150
+ full: { fields: ['id', 'name', 'phone', 'ssn'], access: { roles: ['admin'] } },
151
+ }
152
+ ```
153
+
154
+ ## Validation
155
+
156
+ ```typescript
157
+ validation: {
158
+ name: { minLength: 1, maxLength: 100 },
159
+ capacity: { min: 1, max: 1000 },
160
+ roomType: { enum: ['meeting', 'conference'] },
161
+ email: { email: true },
162
+ }
163
+ ```
164
+
165
+ ## Actions — Custom Business Logic
166
+
167
+ Separate `actions.ts` file:
168
+
169
+ ```typescript
170
+ import { todos } from './todos';
171
+ import { defineActions } from '@quickback/compiler';
172
+ import { z } from 'zod';
173
+
174
+ export default defineActions(todos, {
175
+ complete: {
176
+ description: "Mark todo as complete",
177
+ input: z.object({ completedAt: z.string().datetime().optional() }),
178
+ guard: { roles: ["member", "admin"] },
179
+ execute: async ({ db, record, ctx, input }) => {
180
+ await db.update(todos).set({ completed: true }).where(eq(todos.id, record.id));
181
+ return { success: true };
182
+ },
183
+ },
184
+ });
185
+ ```
186
+
187
+ Record-based: `POST /api/v1/{resource}/:id/{action}`
188
+ Standalone: `standalone: true`, custom `path` and `method`
189
+
190
+ ## CMS Layouts
191
+
192
+ ```typescript
193
+ layouts: {
194
+ default: {
195
+ sections: [
196
+ { label: "Details", columns: 2, fields: ["name", "email"] },
197
+ { label: "Notes", collapsed: true, fields: ["notes"] },
198
+ ],
199
+ },
200
+ }
201
+ ```
202
+
203
+ ## API Reference
204
+
205
+ | Method | Endpoint | Description |
206
+ |--------|----------|-------------|
207
+ | `GET` | `/api/v1/{resource}` | List |
208
+ | `GET` | `/api/v1/{resource}/:id` | Get |
209
+ | `POST` | `/api/v1/{resource}` | Create |
210
+ | `PATCH` | `/api/v1/{resource}/:id` | Update |
211
+ | `DELETE` | `/api/v1/{resource}/:id` | Delete |
212
+
213
+ Query params: `?limit=50&offset=0`, `?status=active`, `?sort=-createdAt`, `?fields=id,name`, `?search=text`
214
+ Filter operators: `.gt`, `.gte`, `.lt`, `.lte`, `.ne`, `.like`, `.in`
215
+
216
+ ## Database Dialects
217
+
218
+ | Stack | Import | Table Function |
219
+ |-------|--------|----------------|
220
+ | Cloudflare D1 / SQLite | `drizzle-orm/sqlite-core` | `sqliteTable` |
221
+ | Supabase / PostgreSQL | `drizzle-orm/pg-core` | `pgTable` |
222
+
223
+ ## CLI Commands
224
+
225
+ ```bash
226
+ quickback create <template> <name> # Create project
227
+ quickback compile # Compile definitions
228
+ quickback docs [topic] # Show documentation
229
+ quickback claude install # Install Claude Code skill
230
+ quickback cursor install # Install Cursor rules
231
+ ```
232
+
233
+ ## Full Documentation
234
+
235
+ https://docs.quickback.dev
@@ -97,12 +97,10 @@ Quickback automatically injects these fields into every table:
97
97
 
98
98
  ---
99
99
 
100
- ## Feature Definitions (Combined Mode)
100
+ ## Feature Definitions
101
101
 
102
102
  Features live in `quickback/features/{name}/` with one file per table using `defineTable()`.
103
103
 
104
- **Important**: Legacy mode (separate schema.ts + resource.ts) is no longer supported.
105
-
106
104
  ### Example: todos.ts
107
105
 
108
106
  ```typescript
@@ -38,7 +38,7 @@ You deeply understand:
38
38
 
39
39
  ## Code Generation
40
40
 
41
- **Combined mode** (the only supported mode): Schema + security in a single file using `defineTable()`.
41
+ Schema + security config in a single file using `defineTable()`.
42
42
 
43
43
  Generate files in `quickback/features/{name}/`:
44
44
  - `{table}.ts` - Drizzle schema + security config via `defineTable()` (DO NOT add audit fields - they're auto-injected)
@@ -196,7 +196,7 @@ Before finishing, verify:
196
196
  - [ ] Validation rules for constrained fields (if needed)
197
197
  - [ ] Layouts for CMS record page field grouping (if needed)
198
198
  - [ ] No audit fields in schema (auto-injected)
199
- - [ ] Using `defineTable()` combined mode (not separate schema.ts + resource.ts)
199
+ - [ ] Using `defineTable()` (not separate schema.ts + resource.ts)
200
200
  - [ ] Actions use `defineActions()` with Zod schemas (not JSON schema)
201
201
 
202
202
  ## Accessing Documentation