@everystack/mcp 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/adding-database.md +36 -23
  2. package/dist/cli.md +44 -3
  3. package/dist/core.md +19 -1
  4. package/dist/database-operations.md +236 -0
  5. package/dist/derived-objects.md +225 -0
  6. package/dist/gates/detectors/embedded-data-bundle.d.ts +13 -0
  7. package/dist/gates/detectors/embedded-data-bundle.d.ts.map +1 -0
  8. package/dist/gates/detectors/embedded-data-bundle.js +56 -0
  9. package/dist/gates/detectors/hand-written-migration.d.ts +24 -0
  10. package/dist/gates/detectors/hand-written-migration.d.ts.map +1 -0
  11. package/dist/gates/detectors/hand-written-migration.js +54 -0
  12. package/dist/gates/detectors/secret-in-public-env.d.ts +12 -0
  13. package/dist/gates/detectors/secret-in-public-env.d.ts.map +1 -0
  14. package/dist/gates/detectors/secret-in-public-env.js +38 -0
  15. package/dist/gates/engine.d.ts +28 -0
  16. package/dist/gates/engine.d.ts.map +1 -0
  17. package/dist/gates/engine.js +74 -0
  18. package/dist/gates/registry.d.ts +14 -0
  19. package/dist/gates/registry.d.ts.map +1 -0
  20. package/dist/gates/registry.js +21 -0
  21. package/dist/gates/telemetry.d.ts +47 -0
  22. package/dist/gates/telemetry.d.ts.map +1 -0
  23. package/dist/gates/telemetry.js +121 -0
  24. package/dist/gates/types.d.ts +67 -0
  25. package/dist/gates/types.d.ts.map +1 -0
  26. package/dist/gates/types.js +14 -0
  27. package/dist/governance/cli.d.ts +57 -0
  28. package/dist/governance/cli.d.ts.map +1 -0
  29. package/dist/governance/cli.js +169 -0
  30. package/dist/governance/grounding.d.ts +78 -0
  31. package/dist/governance/grounding.d.ts.map +1 -0
  32. package/dist/governance/grounding.js +299 -0
  33. package/dist/index.cjs +119 -107
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +94 -0
  37. package/dist/project-claude-md.md +35 -18
  38. package/dist/prompts/add-feature.d.ts +3 -0
  39. package/dist/prompts/add-feature.d.ts.map +1 -0
  40. package/dist/prompts/add-feature.js +154 -0
  41. package/dist/prompts/claude-md.d.ts +12 -0
  42. package/dist/prompts/claude-md.d.ts.map +1 -0
  43. package/dist/prompts/claude-md.js +87 -0
  44. package/dist/prompts/debug.d.ts +3 -0
  45. package/dist/prompts/debug.d.ts.map +1 -0
  46. package/dist/prompts/debug.js +129 -0
  47. package/dist/prompts/deploy.d.ts +3 -0
  48. package/dist/prompts/deploy.d.ts.map +1 -0
  49. package/dist/prompts/deploy.js +118 -0
  50. package/dist/prompts/design-schema.d.ts +3 -0
  51. package/dist/prompts/design-schema.d.ts.map +1 -0
  52. package/dist/prompts/design-schema.js +97 -0
  53. package/dist/prompts/governance-setup.d.ts +9 -0
  54. package/dist/prompts/governance-setup.d.ts.map +1 -0
  55. package/dist/prompts/governance-setup.js +76 -0
  56. package/dist/prompts/index.d.ts +3 -0
  57. package/dist/prompts/index.d.ts.map +1 -0
  58. package/dist/prompts/index.js +20 -0
  59. package/dist/prompts/new-app.d.ts +3 -0
  60. package/dist/prompts/new-app.d.ts.map +1 -0
  61. package/dist/prompts/new-app.js +203 -0
  62. package/dist/prompts/runbook.d.ts +12 -0
  63. package/dist/prompts/runbook.d.ts.map +1 -0
  64. package/dist/prompts/runbook.js +70 -0
  65. package/dist/prompts/secure.d.ts +3 -0
  66. package/dist/prompts/secure.d.ts.map +1 -0
  67. package/dist/prompts/secure.js +219 -0
  68. package/dist/resources/index.d.ts +12 -0
  69. package/dist/resources/index.d.ts.map +1 -0
  70. package/dist/resources/index.js +182 -0
  71. package/dist/schema-patterns.md +92 -106
  72. package/dist/tools/check-environment.d.ts +25 -0
  73. package/dist/tools/check-environment.d.ts.map +1 -0
  74. package/dist/tools/check-environment.js +281 -0
  75. package/dist/tools/index.d.ts +3 -0
  76. package/dist/tools/index.d.ts.map +1 -0
  77. package/dist/tools/index.js +18 -0
  78. package/dist/tools/project-status.d.ts +28 -0
  79. package/dist/tools/project-status.d.ts.map +1 -0
  80. package/dist/tools/project-status.js +138 -0
  81. package/dist/tools/project-validate.d.ts +19 -0
  82. package/dist/tools/project-validate.d.ts.map +1 -0
  83. package/dist/tools/project-validate.js +323 -0
  84. package/dist/tools/schema-analyze.d.ts +46 -0
  85. package/dist/tools/schema-analyze.d.ts.map +1 -0
  86. package/dist/tools/schema-analyze.js +336 -0
  87. package/package.json +3 -3
  88. package/src/gates/detectors/hand-written-migration.ts +29 -13
  89. package/src/index.ts +1 -1
  90. package/src/prompts/add-feature.ts +4 -4
  91. package/src/prompts/claude-md.ts +4 -2
  92. package/src/prompts/debug.ts +3 -4
  93. package/src/prompts/deploy.ts +17 -8
  94. package/src/prompts/design-schema.ts +45 -59
  95. package/src/prompts/new-app.ts +21 -19
  96. package/src/prompts/secure.ts +3 -3
  97. package/src/resources/adding-database.md +36 -23
  98. package/src/resources/cli.md +44 -3
  99. package/src/resources/core.md +19 -1
  100. package/src/resources/database-operations.md +236 -0
  101. package/src/resources/derived-objects.md +225 -0
  102. package/src/resources/index.ts +15 -1
  103. package/src/resources/project-claude-md.md +35 -18
  104. package/src/resources/schema-patterns.md +92 -106
@@ -4,10 +4,10 @@ import { z } from 'zod';
4
4
  export function registerDesignSchemaPrompt(server: McpServer): void {
5
5
  server.prompt(
6
6
  'design-schema',
7
- 'Interactive schema design: plain English description → Drizzle schema + migrations + RLS policies + handler config + testing checklist.',
7
+ 'Interactive schema design (0.4.0): plain English description → declared Models (defineModel + can abilities) + derived descriptors + testing checklist. Authz and handler config are DERIVED from the Models, never hand-written.',
8
8
  {
9
9
  description: z.string().describe('Plain English description of the data model (e.g., "blog with posts, comments, and tags")'),
10
- projectPath: z.string().optional().describe('Absolute path to project root (to analyze existing schema)'),
10
+ projectPath: z.string().optional().describe('Absolute path to project root (to read the existing db/models/)'),
11
11
  },
12
12
  async ({ description, projectPath }) => {
13
13
  return {
@@ -19,81 +19,67 @@ export function registerDesignSchemaPrompt(server: McpServer): void {
19
19
  text: [
20
20
  `Design a database schema for: ${description}`,
21
21
  '',
22
+ 'IMPORTANT (0.4.0): you declare the schema, you do NOT hand-write it. Tables are',
23
+ '`defineModel` in `db/models/`; authorization is `can()` abilities on the Model that',
24
+ 'COMPILE to RLS + grants; the handler config is DERIVED from the Models. Never hand-write',
25
+ '`db/schema.ts`, a SQL migration, `CREATE POLICY`, or `GRANT` — those are generated.',
26
+ '',
22
27
  '## Instructions',
23
28
  '',
24
- '1. Read everystack://schema-patterns for Drizzle schema conventions.',
25
- '2. Read everystack://security for RLS policy patterns.',
26
- '3. Read everystack://handler-options for handler configuration.',
27
- projectPath ? `4. Run schema_analyze with projectPath="${projectPath}" to understand the existing schema.` : '',
29
+ '1. Read everystack://schema-patterns for how to declare TABLES (defineModel, field, can, relations).',
30
+ '2. Read everystack://derived-objects IF the model needs views, materialized views, functions, or triggers.',
31
+ '3. Read everystack://security for the authorization model (how can() abilities become RLS + grants).',
32
+ '4. Read everystack://database-operations for how the declaration reaches a database (db:sync on dev).',
33
+ projectPath ? `5. Read the existing \`db/models/\` under "${projectPath}" to match its conventions before adding to it.` : '',
28
34
  '',
29
35
  '## Deliverables',
30
36
  '',
31
37
  'Generate ALL of the following:',
32
38
  '',
33
- '### 1. Drizzle Schema (db/schema.ts)',
34
- '',
35
- 'Follow these conventions:',
36
- '- UUID primary keys: `uuid(\'id\').primaryKey().defaultRandom()`',
37
- '- Timestamps: `timestamp(\'created_at\', { withTimezone: true }).defaultNow().notNull()`',
38
- '- Soft delete columns: `deletedAt` + `deletedBy` on user-facing tables',
39
- '- Foreign keys with `.references(() => table.column)`',
40
- '- Export all tables as named exports',
41
- '- Add Drizzle `relations()` for SSR query building and API embedding',
42
- '',
43
- '### 2. SQL Migration with RLS',
44
- '',
45
- 'Generate a custom SQL migration that includes:',
39
+ '### 1. Models (db/models/<table>.ts — one file per table)',
46
40
  '',
47
- '```sql',
48
- '-- For each table:',
49
- 'ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;',
41
+ 'Declare each table with `defineModel`, following these conventions:',
42
+ '- UUID primary keys: `id: field.uuid().primaryKey().defaultRandom()`',
43
+ '- Timestamps: `createdAt: field.timestamptz().defaultNow().notNull()`',
44
+ '- Soft delete: a `deletedAt: field.timestamptz()` field opts the table into soft-delete',
45
+ '- Foreign keys via relations: `field.uuid().references(() => Author)` / `belongsTo`/`hasMany`',
46
+ '- Sensitive columns: `.private()` (hidden from the API); write-guarded: `.readonly()`',
47
+ '- Named exports (PascalCase model var, e.g. `export const Post = defineModel(\'posts\', …)`)',
50
48
  '',
51
- '-- Grant minimum required access per role:',
52
- 'GRANT SELECT ON table_name TO anon;',
53
- 'GRANT SELECT, INSERT, UPDATE, DELETE ON table_name TO authenticated;',
54
- 'GRANT ALL ON table_name TO admin;',
49
+ '### 2. Authorization `can()` abilities ON each Model (NOT hand-written RLS)',
55
50
  '',
56
- '-- Policies per access pattern:',
57
- '-- Public read:',
58
- 'CREATE POLICY "anon_select" ON table_name FOR SELECT TO anon USING (deleted_at IS NULL);',
51
+ 'Declare the access pattern as abilities; the compiler emits the RLS policies and GRANTs.',
52
+ 'Every table MUST make its read decision or `db:check` fails it:',
59
53
  '',
60
- '-- Own rows only:',
61
- 'CREATE POLICY "own_rows" ON table_name FOR ALL TO authenticated',
62
- ' USING (user_id = current_setting(\'request.jwt.claims\', true)::json->>\'sub\');',
63
- '',
64
- '-- Admin full access:',
65
- 'CREATE POLICY "admin_all" ON table_name FOR ALL TO admin USING (true);',
54
+ '```ts',
55
+ 'abilities: [',
56
+ " can('read'), // public read (anon + authenticated)",
57
+ " can('read', { owner: 'authorId' }), // rows the caller owns",
58
+ " can('manage', { owner: 'authorId' }), // owner can write their own rows",
59
+ " can('read', { role: 'admin' }), // a specific role only",
60
+ '],',
66
61
  '```',
67
62
  '',
68
- 'Adapt the policies to the specific access patterns for each table.',
63
+ 'A private/operational table declares `private: true` (generated, but not a generic-API',
64
+ 'resource). Row ownership, soft-delete, hidden/protected columns, and relations are all',
65
+ 'DERIVED from the Model into the handler config — do not write a createHandler options blob',
66
+ 'by hand.',
69
67
  '',
70
- '### 3. Handler Configuration',
68
+ '### 3. Derived objects (only if the model needs compute)',
71
69
  '',
72
- 'Generate the createHandler() config snippet:',
73
- '- `exposedTables`: only tables that should be API-accessible',
74
- '- `relations`: for embedding related data in API queries',
75
- '- `rowOwnership`: for user-scoped tables',
76
- '- `softDelete`: for tables with deletedAt columns',
77
- '- `protectedFields`: fields users cannot set directly (role, deletedAt)',
78
- '- `hiddenColumns`: sensitive columns not returned in API responses',
70
+ 'If the design needs a view, materialized view, function, or trigger, declare it as a',
71
+ 'descriptor in `db/models/derived.ts` per everystack://derived-objects NOT as a SQL',
72
+ 'migration. Wire them on `defineModule({ models, derived })`.',
79
73
  '',
80
- '### 4. Testing Checklist',
74
+ '### 4. Testing + apply checklist',
81
75
  '',
82
- 'Generate a testing checklist:',
83
- '- [ ] Anonymous users can read public data',
84
- '- [ ] Anonymous users cannot write any data',
85
- '- [ ] Authenticated users can only read/write their own data',
76
+ '- [ ] Every table declares a read ability or `private: true` (db:check gate)',
77
+ '- [ ] Anonymous users can read only what `can(\'read\')` (no owner/role) allows',
78
+ '- [ ] Owner-scoped rows are invisible and unwritable across users (IDOR)',
86
79
  '- [ ] Soft-deleted rows are hidden from normal queries',
87
- '- [ ] Admin users can access all data',
88
- '- [ ] Foreign key constraints prevent orphaned rows',
89
- '- [ ] RLS policies work with pgSettings claim injection',
90
- '',
91
- 'Test each RLS policy with:',
92
- '```sql',
93
- 'SET LOCAL ROLE authenticated;',
94
- "SELECT set_config('request.jwt.claims', '{\"sub\": \"user-uuid\", \"role\": \"authenticated\"}', true);",
95
- 'SELECT * FROM table_name; -- should only return own rows',
96
- '```',
80
+ '- [ ] `everystack db:sync --database-url "$DATABASE_URL"` applies cleanly on a dev DB',
81
+ '- [ ] `everystack db:check` passes (declared state composes; generated artifacts match)',
82
+ '- [ ] `everystack db:authz:test --stage dev` proves the compiled RLS enforces the abilities',
97
83
  ].filter(Boolean).join('\n'),
98
84
  },
99
85
  },
@@ -106,7 +106,7 @@ export function registerNewAppPrompt(server: McpServer): void {
106
106
  '```',
107
107
  `${effectiveName}/`,
108
108
  '├── app/ # Expo Router pages',
109
- effectiveTier !== 'V1' ? '├── db/ # Schema, migrations, seed' : '',
109
+ effectiveTier !== 'V1' ? '├── db/ # models/ (declared schema), backfills/, seed' : '',
110
110
  '├── server/ # Lambda handlers',
111
111
  effectiveTier !== 'V1' ? '│ └── api.ts # PostgREST handler' : '',
112
112
  effectiveTier === 'V3' ? '│ ├── worker.ts # SQS worker handler' : '',
@@ -117,27 +117,29 @@ export function registerNewAppPrompt(server: McpServer): void {
117
117
  '```',
118
118
  '',
119
119
  effectiveTier !== 'V1' ? [
120
- '### 3. Database Schema',
121
- `Create db/schema.ts with tables for the ${description}.`,
120
+ '### 3. Database Schema — declared Models (0.4.0)',
121
+ `Declare tables for the ${description} as \`defineModel\` in \`db/models/\` (one file per table).`,
122
+ 'Do NOT hand-write db/schema.ts or run drizzle-kit — the schema is DECLARED, then compiled.',
122
123
  'Follow the patterns from everystack://schema-patterns:',
123
- '- UUID primary keys with defaultRandom()',
124
- '- created_at timestamps on all tables',
125
- '- Foreign key references with proper cascading',
126
- '- Relations for both SSR and API query embedding',
124
+ '- `field.uuid().primaryKey().defaultRandom()`; `field.timestamptz().defaultNow().notNull()`',
125
+ '- Foreign keys via `.references(() => Model)` / relations for SSR + API embedding',
126
+ '- Authorization as `can()` abilities ON the Model (compiles to RLS + grants — never hand-written)',
127
+ '- Views/matviews/functions/triggers: descriptors in db/models/derived.ts (everystack://derived-objects)',
128
+ '- Compose in db/models/index.ts: `defineModule({ models, derived })`',
127
129
  '',
128
- '### 4. Migrations',
129
- '- Generate: `npx drizzle-kit generate`',
130
- '- Add RLS policies in a custom SQL migration',
131
- '- Reference the RLS templates from everystack://security',
130
+ '### 4. Apply the schema',
131
+ '- Dev database: `everystack db:sync --database-url "$DATABASE_URL"` (state + authz + compute, one verb)',
132
+ '- CI gate: `everystack db:check`',
133
+ '- Protected stages: `db:plan` `db:apply` (everystack://database-operations)',
134
+ '- No hand-written migration, no CREATE POLICY, no GRANT — all generated from the Models',
132
135
  '',
133
136
  '### 5. Handler Configuration',
134
137
  'Create server/api.ts using createPluginLambdaHandler or createLambdaHandler.',
135
- 'Include:',
138
+ 'The per-table access config (exposedTables, rowOwnership, softDelete, hidden/protected columns,',
139
+ 'relations) is DERIVED from your Models via `deriveHandlerConfig(models)` — do not hand-maintain it.',
140
+ 'Set only the app-level options by hand:',
136
141
  '- auth.verifyToken for JWT verification',
137
142
  '- pgSettings for RLS context injection',
138
- '- exposedTables to limit API surface',
139
- '- rowOwnership for user-scoped mutation control',
140
- '- softDelete for reversible deletes',
141
143
  '',
142
144
  '### 6. Auth Setup',
143
145
  'Read everystack://auth for the full auth flow.',
@@ -148,7 +150,7 @@ export function registerNewAppPrompt(server: McpServer): void {
148
150
  ].join('\n') : '',
149
151
  '## Validation',
150
152
  '',
151
- 'After scaffolding, run the project_validate tool to check for common mistakes.',
153
+ 'After scaffolding, run `check_environment` to confirm prerequisites, and `everystack db:check` to confirm the declared schema composes.',
152
154
  '',
153
155
  '## Run Locally',
154
156
  '',
@@ -200,10 +202,10 @@ export function registerNewAppPrompt(server: McpServer): void {
200
202
  effectiveTier === 'V3' ? '- S3 bucket for file uploads' : '',
201
203
  '',
202
204
  '### Deploy',
203
- 'Read everystack://deployment for the full walkthrough.',
205
+ 'Read everystack://deployment and everystack://database-operations for the full walkthrough.',
204
206
  '1. `pnpm sst deploy --stage dev`',
205
- effectiveTier !== 'V1' ? '2. `everystack db:migrate`' : '',
206
- effectiveTier !== 'V1' ? '3. `everystack db:seed` (dev only)' : '',
207
+ effectiveTier !== 'V1' ? '2. `everystack db:plan --stage dev --out dev.plan.json` → review → `everystack db:apply --plan dev.plan.json --stage dev`' : '',
208
+ effectiveTier !== 'V1' ? '3. `everystack db:seed --stage dev` (dev only)' : '',
207
209
  ].filter(Boolean).join('\n'),
208
210
  },
209
211
  },
@@ -29,8 +29,8 @@ export function registerSecurePrompt(server: McpServer): void {
29
29
  '',
30
30
  '1. Read everystack://security for the complete security model.',
31
31
  '2. Read everystack://auth for JWT authentication details.',
32
- projectPath ? `3. Run project_validate with projectPath="${projectPath}" to find existing security gaps.` : '',
33
- projectPath ? `4. Run schema_analyze with projectPath="${projectPath}" to check schema security.` : '',
32
+ projectPath ? `3. Read the project's \`db/models/\` under "${projectPath}" the \`can()\` abilities ARE the authorization; confirm every table declares a read decision.` : '',
33
+ projectPath ? '4. Run the real security tooling: `everystack db:doctor` (least-privilege + RLS posture), `everystack db:authz:test --stage dev` (the compiled RLS enforces the abilities), and `everystack security:audit`.' : '',
34
34
  '',
35
35
  requested.includes('aws') ? [
36
36
  '## AWS IAM Profiles',
@@ -215,7 +215,7 @@ export function registerSecurePrompt(server: McpServer): void {
215
215
  '',
216
216
  'After setup, verify security:',
217
217
  '',
218
- '1. Run project_validate to check for gaps',
218
+ '1. Run `everystack db:doctor` and `everystack db:authz:test --stage dev` to prove the RLS enforces the declared abilities',
219
219
  '2. Test unauthenticated access returns 401',
220
220
  '3. Test cross-user data isolation with RLS',
221
221
  '4. Verify JWT claims propagate through pgSettings',
@@ -13,7 +13,7 @@ You already have a running Expo app. Now you're adding:
13
13
  - **@everystack/logging** — structured logging so you can see what your app is doing.
14
14
  - **@everystack/security** — device attestation and biometric auth.
15
15
  - **@everystack/query** — React hooks that make it easy to fetch and display data.
16
- - **Drizzle ORM** defines your database tables in TypeScript. You describe what data you want to store, and Drizzle creates the tables for you.
16
+ - **@everystack/model** — declares your database tables in TypeScript with `defineModel`. You describe what data you want to store and who can read/write it, and everystack generates the migration and the typed schema for you.
17
17
 
18
18
  ## Step 1: Install PostgreSQL
19
19
 
@@ -64,24 +64,31 @@ You should see a table with the value `1`. If so, your database is ready.
64
64
  From your project directory:
65
65
 
66
66
  ```bash
67
- pnpm add @everystack/api @everystack/auth @everystack/admin @everystack/logging @everystack/security @everystack/query
67
+ pnpm add @everystack/api @everystack/auth @everystack/admin @everystack/logging @everystack/security @everystack/query @everystack/model
68
68
  pnpm add drizzle-orm
69
- pnpm add -D drizzle-kit
70
69
  ```
71
70
 
72
- ## Step 4: Create your database schema
71
+ ## Step 4: Declare your database schema
73
72
 
74
- The schema defines what data your app stores. Create a file at `db/schema.ts`.
73
+ The schema defines what data your app stores. Create your tables in `db/models/` — one
74
+ `defineModel` per table (for example `db/models/post.ts`), composed onto a `defineModule`
75
+ in `db/models/index.ts`.
75
76
 
76
- A schema is like designing a spreadsheet before you start filling in data. You decide what columns each table has, what type of data goes in each column, and how tables relate to each other.
77
+ A model is like designing a spreadsheet before you start filling in data. You decide what columns each table has, what type of data goes in each column, and how tables relate to each other — plus who can read and write each table.
77
78
 
78
- Read everystack://schema-patterns for design patterns and examples. Key conventions:
79
+ You do **not** hand-write `db/schema.ts` and you do **not** run `drizzle-kit generate` —
80
+ everystack generates the migration and the typed artifact from your Models.
79
81
 
80
- - UUID primary keys with `defaultRandom()`
81
- - `created_at` and `updated_at` timestamps on all tables
82
- - Foreign key references with proper cascading
83
- - Relations defined for both SSR and API query embedding
84
- - Snake_case column names
82
+ Read everystack://schema-patterns for the `defineModel` patterns and examples. Key conventions:
83
+
84
+ - UUID primary keys with `field.uuid().primaryKey().defaultRandom()`
85
+ - `createdAt` and `updatedAt` timestamps on all tables
86
+ - Foreign key references with `.references('users', 'id')`
87
+ - Relations declared on the Model (used for both SSR and API query embedding)
88
+ - Authorization declared with `can()` abilities (compiles to grants + RLS)
89
+
90
+ For views, materialized views, functions, and triggers, read everystack://derived-objects
91
+ — they are declared as descriptors and deploy via `db:reconcile`, not migrations.
85
92
 
86
93
  ## Step 5: Configure the handler
87
94
 
@@ -121,29 +128,35 @@ export async function POST(request: Request) {
121
128
  // ... PATCH, DELETE
122
129
  ```
123
130
 
124
- ## Step 8: Run migrations
131
+ ## Step 8: Move your database to match your Models
125
132
 
126
- Migrations create the actual tables in your database based on your schema.
133
+ `db:sync` makes your local dev database match your checkout tables, authz, and the
134
+ derived layer — in one command. You never run `drizzle-kit` or write a SQL migration.
127
135
 
128
136
  ```bash
129
- npx drizzle-kit generate
130
- npx drizzle-kit migrate
137
+ everystack db:sync --database-url "$DATABASE_URL"
131
138
  ```
132
139
 
133
- The first command generates SQL files from your schema. The second runs them against your database.
140
+ This is the dev edit loop: change `db/models/`, run `db:sync`, test, repeat. When you're
141
+ ready to record the change as a migration for protected stages, run `everystack db:generate`
142
+ (and later reach a deployed stage with `db:plan` → `db:apply`).
143
+
144
+ Read everystack://database-operations for the full workflow — the dev loop, importing data,
145
+ and safely migrating a deployed stage.
134
146
 
135
147
  ## Step 9: Security
136
148
 
137
149
  **This is not optional.** Read everystack://security for the three-layer security model.
138
150
 
139
- Your database needs Row Level Security (RLS) policies. These are rules that control who can see and change what data. Even if your app code has a bug, the database enforces access control.
151
+ Your database needs Row Level Security (RLS) rules that control who can see and change what data. Even if your app code has a bug, the database enforces access control.
140
152
 
141
- At minimum:
142
- - Create database roles (`anon`, `authenticated`, `admin`)
143
- - Add RLS policies to every table
144
- - Set up GRANTs so each role can only access what it should
153
+ In everystack you **declare** this on your Models rather than hand-writing SQL: `can()`
154
+ abilities on each `defineModel` compile to database roles (`anon`, `authenticated`,
155
+ `admin`), GRANTs, and RLS policies, and `db:sync` deploys them. `db:check` (the CI gate)
156
+ refuses a table without RLS. Never hand-write `CREATE ROLE`, `GRANT`, or `CREATE POLICY`.
145
157
 
146
- The security resource has copy-paste SQL templates for common patterns.
158
+ The security resource explains the policies your abilities compile to and the patterns
159
+ behind them.
147
160
 
148
161
  ## Step 10: Verify
149
162
 
@@ -28,11 +28,52 @@ everystack update --channel staging --platform web
28
28
  Flags: `--channel` (default: production), `--message`, `--platform` (ios/android/web/all), `--skip-export`.
29
29
 
30
30
  ### Database
31
+
32
+ You declare tables in `db/models/` (`defineModel`) and derived objects as descriptors;
33
+ these verbs move a database. Full operational guidance: everystack://database-operations.
34
+
35
+ **Schema (declare → deploy)**
36
+ ```bash
37
+ everystack db:sync # Make a dev DB match your checkout — state + authz + compute, one verb
38
+ everystack db:generate # STATE layer (tables) → next migration file (--dry-run prints the SQL, writes nothing)
39
+ everystack db:reconcile # Deploy the compute layer only (views/matviews/functions/triggers)
40
+ everystack db:check # CI gate: declared state composes + generated artifacts match regeneration
41
+ everystack db:fingerprint # Content-address the live base schema vs the Models — MATCH/MISMATCH
42
+ everystack db:diff # The state edge between two declared states — no DB, CI-pure
43
+ ```
44
+
45
+ **Safe remote migration (protected stages)**
46
+ ```bash
47
+ everystack db:plan --stage X --out X.plan.json # Mint a reviewable edge — read-only, ephemeral
48
+ everystack db:apply --plan X.plan.json --stage X # Verify → apply → verify, credential-free via the ops Lambda
49
+ everystack db:approvers --stage X --set "…" # Declare who may run destructive applies (STS-verified)
50
+ ```
51
+
52
+ **Backups & safety**
53
+ ```bash
54
+ everystack db:snapshot --stage X # Physical RDS snapshot (instant DR)
55
+ everystack db:snapshots --stage X # List manual RDS snapshots
56
+ everystack db:backup --stage X # Logical pg_dump → private S3 backups bucket
57
+ everystack db:backups --stage X # List logical backups
58
+ everystack db:backup:download <id> --stage X # Presigned download URL (1h)
59
+ everystack db:restore --from <id> --stage X --confirm # Restore a backup INTO a stage (destructive)
60
+ ```
61
+
62
+ **Local dev databases**
63
+ ```bash
64
+ everystack db:template:refresh # Build the dev template from declared state + seed
65
+ everystack db:branch # Per-git-branch dev DB from the template (--list / --prune)
66
+ everystack db:fork --from-stage src --stage tgt --confirm # Fork a deployed stage's DB into a feature stage
67
+ ```
68
+
69
+ **Data**
31
70
  ```bash
32
- everystack db:migrate # Run migrations via Lambda
33
- everystack db:seed # Seed database (dev only)
71
+ everystack db:seed --stage dev # Declarative seed script (dev only; refuses on production)
72
+ everystack db:backfill --apply # One-shot data moves from db/backfills/*.sql (own record)
73
+ everystack pipeline:run --stage X # Ingest pipeline (credential-free in the ops Lambda)
74
+ everystack db:migrate # Run the generated migration on a deployed stage via Lambda invoke
34
75
  everystack db:psql --stage dev -c "SELECT * FROM posts" # Read-only SQL via Lambda
35
- everystack console --stage dev # Interactive REPL with db + schema
76
+ everystack console --stage dev # Interactive REPL with db + schema
36
77
  ```
37
78
 
38
79
  The REPL has `db`, `schema`, `eq`, `and`, `or`, `gt`, `lt`, `count`, `sum`, `avg`, `sql`, `desc`, `asc` in scope.
@@ -158,11 +158,24 @@ const { data } = await api.rpc('timeline', { limit: 20 });
158
158
 
159
159
  All infrastructure commands use **AWS IAM credentials** (not shared secrets).
160
160
 
161
+ You declare tables in `db/models/` with `defineModel` and the derived layer as descriptors
162
+ (see everystack://derived-objects); the CLI moves the database — you never run
163
+ `drizzle-kit` or hand-write a migration. Full operational guidance:
164
+ everystack://database-operations.
165
+
161
166
  | Command | What it does |
162
167
  |---------|-------------|
163
168
  | `everystack update --channel production` | OTA deploy (no infrastructure changes) |
164
- | `everystack db:migrate` | Run Drizzle migrations via Lambda invoke |
169
+ | `everystack db:sync` | Dev DB your checkout (state + authz + compute), one verb |
170
+ | `everystack db:generate` | STATE layer (tables) → next migration file |
171
+ | `everystack db:reconcile` | Deploy the compute layer (views/matviews/functions/triggers) |
172
+ | `everystack db:check` | CI gate: declared state composes + artifacts match regeneration |
173
+ | `everystack db:plan --stage X` | Mint a reviewable, fingerprint-pinned edge (read-only) |
174
+ | `everystack db:apply --plan … --stage X` | Verify → apply → verify, credential-free via the ops Lambda |
175
+ | `everystack db:snapshot / db:backup --stage X` | Physical RDS snapshot / logical pg_dump before a risky migration |
165
176
  | `everystack db:seed` | Seed database via Lambda invoke (dev only) |
177
+ | `everystack db:backfill --apply` | One-shot data moves from `db/backfills/*.sql` |
178
+ | `everystack db:migrate` | Run the generated migration on a deployed stage via Lambda invoke |
166
179
  | `everystack db:psql --stage dev -c "SQL"` | Execute read-only SQL via Lambda |
167
180
  | `everystack console --stage dev` | Interactive REPL with db + schema in scope |
168
181
  | `everystack logs:errors --stage dev` | Query recent error logs |
@@ -173,6 +186,11 @@ All infrastructure commands use **AWS IAM credentials** (not shared secrets).
173
186
  | `everystack diag URL` | Diagnose deployed page freshness |
174
187
  | `everystack analyze:ssr` | Static analysis for SSR anti-patterns |
175
188
 
189
+ On a dev database you `db:sync` freely; a protected stage takes `db:plan` → `db:apply`
190
+ (fingerprint-verified, snapshot + approver gates on destructive plans); `db:check` is the
191
+ per-PR CI gate; `db:reconcile` deploys compute; `db:seed`/`db:backfill` move data;
192
+ `db:snapshot`/`db:backup` are the safety net.
193
+
176
194
  ## Key Patterns
177
195
 
178
196
  **Schema-agnostic.** The library knows nothing about your tables. You pass your Drizzle schema to `createHandler()`. Your schema, your migrations, your database.