@rebasepro/cli 0.5.0 → 0.6.1

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 (61) hide show
  1. package/dist/commands/init.d.ts +13 -0
  2. package/dist/commands/skills.d.ts +1 -0
  3. package/dist/index.es.js +1631 -1308
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/utils/package-manager.d.ts +2 -0
  6. package/package.json +17 -16
  7. package/skills/rebase-admin/SKILL.md +710 -0
  8. package/skills/rebase-api/SKILL.md +662 -0
  9. package/skills/rebase-api/references/.gitkeep +3 -0
  10. package/skills/rebase-auth/SKILL.md +1143 -0
  11. package/skills/rebase-auth/references/.gitkeep +3 -0
  12. package/skills/rebase-backend-postgres/SKILL.md +633 -0
  13. package/skills/rebase-backend-postgres/references/.gitkeep +3 -0
  14. package/skills/rebase-basics/SKILL.md +749 -0
  15. package/skills/rebase-basics/references/.gitkeep +3 -0
  16. package/skills/rebase-collections/SKILL.md +1328 -0
  17. package/skills/rebase-collections/references/.gitkeep +3 -0
  18. package/skills/rebase-cron-jobs/SKILL.md +699 -0
  19. package/skills/rebase-cron-jobs/references/.gitkeep +1 -0
  20. package/skills/rebase-custom-functions/SKILL.md +233 -0
  21. package/skills/rebase-deployment/SKILL.md +885 -0
  22. package/skills/rebase-deployment/references/.gitkeep +3 -0
  23. package/skills/rebase-design-language/SKILL.md +692 -0
  24. package/skills/rebase-email/SKILL.md +701 -0
  25. package/skills/rebase-email/references/.gitkeep +1 -0
  26. package/skills/rebase-entity-history/SKILL.md +485 -0
  27. package/skills/rebase-entity-history/references/.gitkeep +1 -0
  28. package/skills/rebase-local-env-setup/SKILL.md +189 -0
  29. package/skills/rebase-local-env-setup/references/.gitkeep +3 -0
  30. package/skills/rebase-realtime/SKILL.md +755 -0
  31. package/skills/rebase-realtime/references/.gitkeep +3 -0
  32. package/skills/rebase-sdk/SKILL.md +594 -0
  33. package/skills/rebase-sdk/references/.gitkeep +0 -0
  34. package/skills/rebase-storage/SKILL.md +765 -0
  35. package/skills/rebase-storage/references/.gitkeep +3 -0
  36. package/skills/rebase-studio/SKILL.md +746 -0
  37. package/skills/rebase-studio/references/.gitkeep +3 -0
  38. package/skills/rebase-ui-components/SKILL.md +1488 -0
  39. package/skills/rebase-ui-components/references/.gitkeep +3 -0
  40. package/skills/rebase-webhooks/SKILL.md +623 -0
  41. package/skills/rebase-webhooks/references/.gitkeep +1 -0
  42. package/templates/template/AGENTS.md +2 -0
  43. package/templates/template/CLAUDE.md +2 -0
  44. package/templates/template/ai-instructions.md +6 -3
  45. package/templates/template/backend/package.json +1 -1
  46. package/templates/template/backend/src/env.ts +1 -1
  47. package/templates/template/backend/src/index.ts +9 -6
  48. package/templates/template/config/collections/presets/ecommerce/orders.ts +15 -5
  49. package/templates/template/config/collections/presets/ecommerce/products.ts +9 -3
  50. package/templates/template/config/collections/users.ts +7 -10
  51. package/templates/template/frontend/package.json +2 -2
  52. package/templates/template/frontend/src/App.tsx +1 -7
  53. package/templates/template/frontend/vite.config.ts +0 -1
  54. package/templates/template/package.json +1 -0
  55. package/dist/commands/cli.test.d.ts +0 -1
  56. package/dist/commands/dev.test.d.ts +0 -1
  57. package/dist/commands/init.test.d.ts +0 -1
  58. package/dist/index.cjs +0 -1575
  59. package/dist/index.cjs.map +0 -1
  60. package/dist/utils/package-manager.test.d.ts +0 -1
  61. package/dist/utils/project.test.d.ts +0 -1
@@ -0,0 +1,485 @@
1
+ ---
2
+ name: rebase-entity-history
3
+ description: Guide for tracking and reverting entity changes with Rebase's built-in history/audit-log system. Use this skill when the user needs entity versioning, change tracking, audit logs, reverting to previous versions, or understanding how history snapshots work.
4
+ ---
5
+
6
+ # Rebase Entity History
7
+
8
+ Rebase includes a built-in entity history system that records snapshots of every create, update, and delete operation. History entries are stored in a dedicated PostgreSQL table and exposed via REST API endpoints. The Studio admin panel provides a visual history tab with one-click revert.
9
+
10
+ > **IMPORTANT FOR AGENTS:** Entity history requires **two** things to be enabled: (1) the global `history` flag in the backend config, AND (2) `history: true` on each individual collection. If either is missing, no history is recorded for that collection.
11
+
12
+ ## Enabling History
13
+
14
+ ### Step 1 — Enable History Globally (Backend Config)
15
+
16
+ Add `history: true` (or a configuration object) to `initializeRebaseBackend()`:
17
+
18
+ ```typescript
19
+ import { initializeRebaseBackend } from "@rebasepro/server-core";
20
+
21
+ await initializeRebaseBackend({
22
+ app,
23
+ server,
24
+ database: createPostgresAdapter({ connectionString: env.DATABASE_URL }),
25
+ collections: [...collections],
26
+
27
+ // ── Enable entity history globally ──
28
+ history: true,
29
+
30
+ auth: { /* ... */ },
31
+ });
32
+ ```
33
+
34
+ The `history` property accepts either:
35
+
36
+ | Value | Behavior |
37
+ |-------|----------|
38
+ | `true` | Enable history with default retention settings |
39
+ | `{ retention: number }` | Enable history with a custom TTL (in days) for automatic pruning |
40
+ | `false` / `undefined` | History disabled (default) |
41
+
42
+ ```typescript
43
+ // Custom retention: prune entries older than 30 days
44
+ history: { retention: 30 },
45
+ ```
46
+
47
+ ### Step 2 — Enable History Per-Collection
48
+
49
+ On each collection that should be tracked, set `history: true`:
50
+
51
+ ```typescript
52
+ import { PostgresCollection } from "@rebasepro/types";
53
+
54
+ const productsCollection: PostgresCollection = {
55
+ slug: "products",
56
+ name: "Products",
57
+ table: "products",
58
+
59
+ // ── Enable history for this collection ──
60
+ history: true,
61
+
62
+ properties: {
63
+ name: { dataType: "string", name: "Name" },
64
+ price: { dataType: "number", name: "Price" },
65
+ status: { dataType: "string", name: "Status" },
66
+ },
67
+ };
68
+ ```
69
+
70
+ > **WARNING FOR AGENTS:** Setting `history: true` on a collection has **no effect** if the global `history` flag is not also set in the backend config. Both must be enabled.
71
+
72
+ ## How History Recording Works
73
+
74
+ History is recorded **fire-and-forget** — it never blocks or slows down the main save/delete operation. Errors during history recording are logged to the console but do not propagate.
75
+
76
+ ### When History Entries Are Created
77
+
78
+ | Operation | Action Recorded | What's Stored |
79
+ |-----------|----------------|---------------|
80
+ | Create entity | `"create"` | Full entity values |
81
+ | Update entity | `"update"` | New values + previous values + list of changed fields |
82
+ | Delete entity | `"delete"` | Final entity values before deletion |
83
+
84
+ ### Skipped Updates
85
+
86
+ Updates that produce **zero actual field changes** are silently skipped — no history entry is created. The system uses deep structural comparison (not reference equality) to detect whether values actually changed, including nested objects, arrays, and Date values.
87
+
88
+ ### Changed Field Detection
89
+
90
+ For updates, the system compares old and new values field-by-field and records only the keys that changed. Internal metadata fields (prefixed with `__`) are excluded from change detection.
91
+
92
+ ## History Entry Format
93
+
94
+ Each history entry has the following structure:
95
+
96
+ | Field | Type | Description |
97
+ |-------|------|-------------|
98
+ | `id` | `string` | UUID primary key of the history entry |
99
+ | `table_name` | `string` | The collection slug / table path |
100
+ | `entity_id` | `string` | The ID of the entity this entry belongs to |
101
+ | `action` | `"create" \| "update" \| "delete"` | What operation was performed |
102
+ | `changed_fields` | `string[] \| null` | Array of field names that changed (only for updates) |
103
+ | `values` | `Record<string, unknown> \| null` | Full entity values snapshot at the time of the change |
104
+ | `previous_values` | `Record<string, unknown> \| null` | Previous entity values (only for updates) |
105
+ | `updated_by` | `string \| null` | UID of the user who made the change |
106
+ | `updated_at` | `string` (ISO 8601) | Timestamp of when the change was recorded |
107
+
108
+ ### Example History Entry (JSON)
109
+
110
+ ```json
111
+ {
112
+ "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
113
+ "table_name": "products",
114
+ "entity_id": "42",
115
+ "action": "update",
116
+ "changed_fields": ["price", "status"],
117
+ "values": {
118
+ "name": "Widget",
119
+ "price": 29.99,
120
+ "status": "active"
121
+ },
122
+ "previous_values": {
123
+ "name": "Widget",
124
+ "price": 19.99,
125
+ "status": "draft"
126
+ },
127
+ "updated_by": "user-uuid-here",
128
+ "updated_at": "2025-01-15T10:30:00.000Z"
129
+ }
130
+ ```
131
+
132
+ ## REST API Endpoints
133
+
134
+ History endpoints are mounted under the data router at `{basePath}/data/:slug/:entityId/history`. They require the same authentication as regular data routes.
135
+
136
+ ### List History Entries
137
+
138
+ ```
139
+ GET /api/data/:slug/:entityId/history
140
+ ```
141
+
142
+ | Query Parameter | Type | Default | Description |
143
+ |-----------------|------|---------|-------------|
144
+ | `limit` | `number` | `20` | Number of entries to return (max `100`) |
145
+ | `offset` | `number` | `0` | Number of entries to skip |
146
+
147
+ **Response:**
148
+
149
+ ```json
150
+ {
151
+ "data": [
152
+ {
153
+ "id": "abc-123",
154
+ "table_name": "products",
155
+ "entity_id": "42",
156
+ "action": "update",
157
+ "changed_fields": ["price"],
158
+ "values": { "name": "Widget", "price": 29.99 },
159
+ "previous_values": { "name": "Widget", "price": 19.99 },
160
+ "updated_by": "user-uuid",
161
+ "updated_at": "2025-01-15T10:30:00.000Z"
162
+ }
163
+ ],
164
+ "meta": {
165
+ "total": 47,
166
+ "limit": 20,
167
+ "offset": 0,
168
+ "hasMore": true
169
+ }
170
+ }
171
+ ```
172
+
173
+ **Error Responses:**
174
+
175
+ | Status | Condition |
176
+ |--------|-----------|
177
+ | `404` | Collection slug not found |
178
+ | `400` | History not enabled for this collection |
179
+
180
+ ### Revert to a Historical Version
181
+
182
+ ```
183
+ POST /api/data/:slug/:entityId/history/:historyId/revert
184
+ ```
185
+
186
+ No request body is needed. The server fetches the stored `values` from the history entry and saves them through the normal entity save path.
187
+
188
+ **Response:**
189
+
190
+ ```json
191
+ {
192
+ "data": {
193
+ "id": "42",
194
+ "values": { "name": "Widget", "price": 19.99, "status": "draft" }
195
+ },
196
+ "meta": {
197
+ "reverted_from": "abc-123"
198
+ }
199
+ }
200
+ ```
201
+
202
+ **Error Responses:**
203
+
204
+ | Status | Condition |
205
+ |--------|-----------|
206
+ | `404` | Collection or history entry not found |
207
+ | `400` | History not enabled for the collection |
208
+ | `400` | History entry belongs to a different entity (cross-entity revert blocked) |
209
+ | `400` | History entry has no stored values |
210
+
211
+ > **IMPORTANT FOR AGENTS:** Reverting goes through the **normal save path**, which means: (1) it triggers all `beforeSave` / `afterSave` callbacks, (2) it creates a **new history entry** for the revert operation itself, providing a complete audit trail, and (3) it notifies real-time subscribers of the change.
212
+
213
+ ### Example: Fetch and Revert via cURL
214
+
215
+ ```bash
216
+ # List history for entity 42 in the "products" collection
217
+ curl -H "Authorization: Bearer $TOKEN" \
218
+ "http://localhost:3001/api/data/products/42/history?limit=10&offset=0"
219
+
220
+ # Revert entity 42 to the state captured in history entry "abc-123"
221
+ curl -X POST \
222
+ -H "Authorization: Bearer $TOKEN" \
223
+ "http://localhost:3001/api/data/products/42/history/abc-123/revert"
224
+ ```
225
+
226
+ ### Example: Fetch via JavaScript (fetch API)
227
+
228
+ ```typescript
229
+ async function getEntityHistory(slug: string, entityId: string, token: string) {
230
+ const response = await fetch(
231
+ `http://localhost:3001/api/data/${slug}/${entityId}/history?limit=20&offset=0`,
232
+ { headers: { Authorization: `Bearer ${token}` } }
233
+ );
234
+ const result = await response.json();
235
+ // result.data — array of HistoryEntryData
236
+ // result.meta — { total, limit, offset, hasMore }
237
+ return result;
238
+ }
239
+
240
+ async function revertEntity(slug: string, entityId: string, historyId: string, token: string) {
241
+ const response = await fetch(
242
+ `http://localhost:3001/api/data/${slug}/${entityId}/history/${historyId}/revert`,
243
+ {
244
+ method: "POST",
245
+ headers: { Authorization: `Bearer ${token}` },
246
+ }
247
+ );
248
+ const result = await response.json();
249
+ // result.data — the reverted entity
250
+ // result.meta.reverted_from — the history entry ID used
251
+ return result;
252
+ }
253
+ ```
254
+
255
+ ## Pagination
256
+
257
+ History entries are returned in **reverse chronological order** (newest first).
258
+
259
+ | Parameter | Default | Maximum | Minimum |
260
+ |-----------|---------|---------|---------|
261
+ | `limit` | `20` | `100` | N/A (clamped with `Math.min`) |
262
+ | `offset` | `0` | N/A | `0` (clamped with `Math.max`) |
263
+
264
+ Use the `meta.hasMore` boolean in the response to determine if more pages are available:
265
+
266
+ ```typescript
267
+ let offset = 0;
268
+ const limit = 20;
269
+ let allEntries = [];
270
+
271
+ while (true) {
272
+ const result = await fetch(`/api/data/products/42/history?limit=${limit}&offset=${offset}`);
273
+ const json = await result.json();
274
+ allEntries.push(...json.data);
275
+
276
+ if (!json.meta.hasMore) break;
277
+ offset += limit;
278
+ }
279
+ ```
280
+
281
+ ## Database Storage
282
+
283
+ ### Table Schema
284
+
285
+ History data is stored in a dedicated table in the `rebase` schema:
286
+
287
+ ```sql
288
+ -- Auto-created on startup when history is enabled
289
+ CREATE TABLE IF NOT EXISTS rebase.entity_history (
290
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
291
+ table_name TEXT NOT NULL,
292
+ entity_id TEXT NOT NULL,
293
+ action TEXT NOT NULL, -- 'create', 'update', or 'delete'
294
+ changed_fields TEXT[], -- array of changed field names (updates only)
295
+ "values" JSONB, -- full entity values snapshot
296
+ previous_values JSONB, -- previous values (updates only)
297
+ updated_by TEXT, -- user UID who made the change
298
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
299
+ );
300
+
301
+ -- Indexes for efficient lookups
302
+ CREATE INDEX IF NOT EXISTS idx_history_entity
303
+ ON rebase.entity_history(table_name, entity_id);
304
+
305
+ CREATE INDEX IF NOT EXISTS idx_history_time
306
+ ON rebase.entity_history(table_name, entity_id, updated_at DESC);
307
+ ```
308
+
309
+ > **IMPORTANT FOR AGENTS:** The `rebase.entity_history` table is **auto-created** on server startup when history is enabled. You do NOT need to create it manually or include it in migrations. The `rebase` schema is also created automatically if it doesn't exist.
310
+
311
+ ### Storage Characteristics
312
+
313
+ - **Values are stored as JSONB** — full snapshots, not diffs. This makes revert simple and reliable but uses more storage.
314
+ - **All collections share one table** — the `table_name` column distinguishes between collections.
315
+ - **Entity IDs are stored as text** — regardless of the original column type.
316
+ - **Indexes** cover `(table_name, entity_id)` and `(table_name, entity_id, updated_at DESC)` for fast per-entity lookups.
317
+
318
+ ## Retention and Automatic Pruning
319
+
320
+ The history service automatically prunes old entries to prevent unbounded storage growth. Pruning happens **non-blocking** after every insert (per-entity scope).
321
+
322
+ ### Retention Configuration
323
+
324
+ | Setting | Type | Default | Description |
325
+ |---------|------|---------|-------------|
326
+ | `maxEntries` | `number` | `200` | Maximum entries kept per entity. Oldest pruned first |
327
+ | `ttlDays` | `number` | `90` | Entries older than this many days are deleted |
328
+
329
+ ### How Pruning Works
330
+
331
+ After every history insert, two pruning passes run in the background for that specific entity:
332
+
333
+ 1. **TTL pass** — Delete entries older than `ttlDays`
334
+ 2. **Max entries pass** — Keep only the newest `maxEntries` entries, delete the rest
335
+
336
+ Pruning errors are logged but never block the main operation.
337
+
338
+ ### Configuring Retention
339
+
340
+ Pass the `retention` option (in days) through the global history config:
341
+
342
+ ```typescript
343
+ await initializeRebaseBackend({
344
+ // ...
345
+ history: { retention: 30 }, // TTL of 30 days
346
+ });
347
+ ```
348
+
349
+ This sets the `ttlDays` value. The `maxEntries` default of `200` is currently not configurable through the backend config and uses the service default.
350
+
351
+ ### Global Pruning
352
+
353
+ The `HistoryService` also exposes a `pruneExpired()` method for global TTL-based cleanup (deletes expired entries across ALL entities in one sweep). This is intended to be called periodically — e.g., from a cron job:
354
+
355
+ ```typescript
356
+ // In a cron job handler (e.g., backend/src/crons/prune-history.ts)
357
+ import { rebase } from "@rebasepro/server-core";
358
+
359
+ export default {
360
+ schedule: "0 3 * * *", // Daily at 3 AM
361
+ handler: async () => {
362
+ // Note: requires direct access to the history service via driver internals
363
+ // This is an advanced pattern — the global prune is automatic per-entity
364
+ console.log("History pruning handled automatically per-entity on insert");
365
+ }
366
+ };
367
+ ```
368
+
369
+ ## Studio Integration
370
+
371
+ When history is enabled for a collection, Rebase Studio automatically adds a **History tab** in the entity edit view. This tab:
372
+
373
+ - Displays a paginated list of history entries with infinite scroll
374
+ - Shows the action type, changed fields, timestamp, and user who made the change
375
+ - Provides a **Revert** button on each entry with a confirmation dialog
376
+ - After revert, resets the form with the restored values (no page refresh needed)
377
+ - Warns users to save or discard unsaved changes before reverting
378
+
379
+ No additional configuration is needed — the History tab appears automatically for any collection with `history: true`.
380
+
381
+ ## Client SDK Usage
382
+
383
+ There is currently **no dedicated client SDK method** for entity history. History is accessed via the REST API directly (as shown in the endpoints section above).
384
+
385
+ The Studio admin panel uses an internal `useEntityHistory` React hook that:
386
+ - Fetches history from `GET /api/data/:slug/:entityId/history`
387
+ - Supports pagination via offset-based loading
388
+ - Provides a `revert()` function that calls `POST /api/data/:slug/:entityId/history/:historyId/revert`
389
+
390
+ For custom client applications, use `fetch()` directly against the REST endpoints with your auth token.
391
+
392
+ ## Complete Setup Example
393
+
394
+ ```typescript
395
+ // backend/src/index.ts
396
+ import { Hono } from "hono";
397
+ import { serve } from "@hono/node-server";
398
+ import { initializeRebaseBackend, loadEnv } from "@rebasepro/server-core";
399
+ import { createPostgresAdapter } from "@rebasepro/server-postgresql";
400
+ import { defaultUsersCollection } from "@rebasepro/common";
401
+ import dotenv from "dotenv";
402
+
403
+ dotenv.config({ path: "../../.env" });
404
+ const env = loadEnv();
405
+
406
+ const app = new Hono();
407
+ const server = serve({ fetch: app.fetch, port: env.PORT });
408
+
409
+ // Collection with history enabled
410
+ const productsCollection = {
411
+ slug: "products",
412
+ name: "Products",
413
+ table: "products",
414
+ history: true, // ← Per-collection opt-in
415
+ properties: {
416
+ name: { dataType: "string" as const, name: "Name" },
417
+ price: { dataType: "number" as const, name: "Price" },
418
+ description: { dataType: "string" as const, name: "Description" },
419
+ },
420
+ };
421
+
422
+ // Collection WITHOUT history
423
+ const logsCollection = {
424
+ slug: "logs",
425
+ name: "Logs",
426
+ table: "logs",
427
+ // history: false (default) — high-volume tables shouldn't track history
428
+ properties: {
429
+ message: { dataType: "string" as const, name: "Message" },
430
+ level: { dataType: "string" as const, name: "Level" },
431
+ },
432
+ };
433
+
434
+ await initializeRebaseBackend({
435
+ app,
436
+ server,
437
+ database: createPostgresAdapter({
438
+ connectionString: env.DATABASE_URL,
439
+ }),
440
+ collections: [productsCollection, logsCollection, defaultUsersCollection],
441
+
442
+ // ── Enable history globally with 60-day retention ──
443
+ history: { retention: 60 },
444
+
445
+ auth: {
446
+ collection: defaultUsersCollection,
447
+ jwtSecret: env.JWT_SECRET,
448
+ serviceKey: env.REBASE_SERVICE_KEY,
449
+ },
450
+ });
451
+
452
+ console.log(`Server running at http://localhost:${env.PORT}`);
453
+ ```
454
+
455
+ ## Performance Considerations
456
+
457
+ ### Write Performance
458
+
459
+ - History recording is **fire-and-forget** — it runs asynchronously and never blocks the save/delete response.
460
+ - For updates, the system fetches the **previous entity values** before saving (to compute `changed_fields` and store `previous_values`). This adds one extra `SELECT` query per update.
461
+ - Updates with zero actual changes are skipped entirely — no history entry is created.
462
+
463
+ ### Storage Growth
464
+
465
+ - Each history entry stores **full JSONB snapshots** of both current and previous values. For entities with large text fields or complex nested structures, this can grow quickly.
466
+ - Default retention limits: **200 entries per entity** and **90 days TTL**. Adjust these based on your use case.
467
+ - All collections share the single `rebase.entity_history` table — monitor its size with:
468
+
469
+ ```sql
470
+ SELECT pg_size_pretty(pg_total_relation_size('rebase.entity_history'));
471
+ ```
472
+
473
+ ### Recommendations
474
+
475
+ | Scenario | Recommendation |
476
+ |----------|---------------|
477
+ | High-write collections (logs, analytics, events) | Do NOT enable `history: true` — the volume will overwhelm storage |
478
+ | Content/CMS collections (articles, products, pages) | Enable history — great for audit trails and undo |
479
+ | User-facing data (orders, profiles) | Enable history — useful for compliance and support |
480
+ | Large text fields (markdown, HTML, JSON blobs) | Consider shorter retention (`history: { retention: 14 }`) to limit storage |
481
+
482
+ ## References
483
+
484
+ - **Documentation:** [rebase.pro/docs](https://rebase.pro/docs)
485
+ - **GitHub:** [github.com/rebasepro/rebase](https://github.com/rebasepro/rebase)
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: rebase-local-env-setup
3
+ description: Bare minimum INITIAL setup for getting started with Rebase (Node.js, pnpm, PostgreSQL, Docker). Use ONLY for first-time setup. For updating or troubleshooting an existing environment, use the rebase-basics skill instead.
4
+ ---
5
+
6
+ # Rebase Local Environment Setup
7
+
8
+ This skill documents the bare minimum setup required for a full Rebase development experience. Before starting to use any Rebase features, you MUST verify that each of the following steps has been completed.
9
+
10
+ > **IMPORTANT FOR AGENTS:** This skill is for INITIAL setup only. For day-to-day development, CLI commands, schema workflow, and troubleshooting, use the `rebase-basics` skill instead.
11
+
12
+ ## Monorepo Structure
13
+
14
+ Rebase is a **pnpm monorepo**. Understanding the layout is essential before setup:
15
+
16
+ ```
17
+ rebase/
18
+ ├── app/ # The main application
19
+ │ ├── .env.example # Full env var reference — copy to .env
20
+ │ ├── .env # Your local env config (git-ignored)
21
+ │ ├── backend/ # Hono API server (runs on port 3001)
22
+ │ ├── frontend/ # Vite + React UI (runs on port 5173)
23
+ │ ├── config/
24
+ │ │ └── collections/ # Collection definitions (schema-as-code)
25
+ │ └── generated/ # Auto-generated SDK, Drizzle schema, etc.
26
+ ├── packages/ # Shared libraries (workspace packages)
27
+ │ ├── cli/ # @rebasepro/cli — provides the `rebase` binary
28
+ │ ├── server-core/ # Core server framework, env loading
29
+ │ ├── server-postgresql/ # PostgreSQL adapter (Drizzle ORM)
30
+ │ ├── studio/ # Studio admin panel
31
+ │ ├── ui/ # @rebasepro/ui component library
32
+ │ ├── client/ # Client SDK
33
+ │ └── ... # Other packages (auth, types, utils, etc.)
34
+ ├── pnpm-workspace.yaml # Workspace configuration
35
+ └── package.json # Root package.json
36
+ ```
37
+
38
+ ## 1. Verify Node.js
39
+
40
+ - **Action**: Run `node --version`.
41
+ - **Required**: Node.js **22 LTS** (the version used in the production Dockerfile). Node >= 20 works but 22 is recommended.
42
+ - **Handling**: If Node.js is missing or < v22:
43
+
44
+ **Recommended: Use a Node Version Manager**
45
+
46
+ **For macOS or Linux:**
47
+ 1. Guide the user to the [official nvm repository](https://github.com/nvm-sh/nvm#installing-and-updating).
48
+ 2. Request the user to manually install `nvm` and reply when finished. **Stop and wait** for the user's confirmation.
49
+ 3. Make `nvm` available in the current terminal session:
50
+ ```bash
51
+ source ~/.zshrc # For Zsh
52
+ source ~/.bashrc # For Bash
53
+ ```
54
+ 4. Install Node.js:
55
+ ```bash
56
+ nvm install 22
57
+ nvm use 22
58
+ ```
59
+
60
+ **For Windows:**
61
+ 1. Guide the user to download and install [nvm-windows](https://github.com/coreybutler/nvm-windows/releases).
62
+ 2. Request the user to manually install and reply when finished.
63
+
64
+ ## 2. Verify pnpm
65
+
66
+ Rebase uses pnpm exclusively as its package manager. Never use npm or yarn.
67
+
68
+ - **Action**: Run `pnpm --version`.
69
+ - **Handling**: If pnpm is not installed:
70
+ ```bash
71
+ npm install -g pnpm
72
+ ```
73
+ - **Verify**: Run `pnpm --version` again to confirm.
74
+
75
+ ## 3. Verify PostgreSQL
76
+
77
+ Rebase's backend requires a PostgreSQL database (v14+).
78
+
79
+ ### Option A: Docker (Recommended)
80
+
81
+ > **IMPORTANT FOR AGENTS:** Docker requires **Docker Desktop** (macOS/Windows) or an alternative like **colima** (macOS). If `docker info` fails, guide the user to install [Docker Desktop](https://www.docker.com/products/docker-desktop/) or run `brew install colima && colima start`.
82
+
83
+ ```bash
84
+ # Check if Docker is running
85
+ docker info
86
+
87
+ # Start a PostgreSQL container
88
+ docker run --name rebase-postgres \
89
+ -e POSTGRES_USER=postgres \
90
+ -e POSTGRES_PASSWORD=postgres \
91
+ -e POSTGRES_DB=rebase \
92
+ -p 5432:5432 \
93
+ -d postgres:17
94
+ ```
95
+
96
+ ### Option B: Local Installation
97
+
98
+ - **macOS**: `brew install postgresql@17 && brew services start postgresql@17`
99
+ - If 17 is unavailable: `brew install postgresql@16 && brew services start postgresql@16`
100
+ - **Linux**: `sudo apt-get install postgresql` (installs the distro default, typically 14–16)
101
+ - **Windows**: Download from [postgresql.org](https://www.postgresql.org/download/)
102
+
103
+ ### Verify Connection
104
+
105
+ ```bash
106
+ psql -h localhost -U postgres -d rebase -c "SELECT 1;"
107
+ ```
108
+
109
+ ## 4. Configure Environment Variables
110
+
111
+ Rebase ships an `.env.example` in the `app/` directory with every variable documented. The recommended approach:
112
+
113
+ ```bash
114
+ cp app/.env.example app/.env
115
+ ```
116
+
117
+ Then edit `app/.env` with your local values. The **minimum** required variables for local dev:
118
+
119
+ | Variable | Example Value | Notes |
120
+ |---|---|---|
121
+ | `DATABASE_URL` | `postgresql://postgres:postgres@localhost:5432/rebase` | **Required.** Must be a valid URL. |
122
+ | `JWT_SECRET` | *(any string ≥ 32 characters)* | If left blank, an ephemeral secret is auto-generated in dev mode — **sessions are invalidated on every server restart**. Set an explicit value for persistent sessions. |
123
+ | `VITE_API_URL` | `http://localhost:3001` | Must match the backend URL. The backend defaults to port `3001`. |
124
+ | `PORT` | `3001` | Backend listen port (default: `3001`). |
125
+ | `FRONTEND_URL` | `http://localhost:5173` | Used in password-reset / verification emails. |
126
+
127
+ > **WARNING FOR AGENTS:** `JWT_SECRET` must be ≥ 32 characters (enforced by Zod validation in `packages/server-core/src/env.ts`). In dev mode, if `JWT_SECRET` is empty the server auto-generates a random one — but this means **all user sessions are lost on every restart**. Always recommend setting an explicit value:
128
+ > ```env
129
+ > JWT_SECRET=change-me-to-a-random-string-at-least-32-chars-long!!
130
+ > ```
131
+
132
+ A minimal `.env` looks like:
133
+
134
+ ```env
135
+ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/rebase
136
+ JWT_SECRET=change-me-to-a-random-string-at-least-32-chars-long!!
137
+ VITE_API_URL=http://localhost:3001
138
+ ```
139
+
140
+ ## 5. Install Dependencies
141
+
142
+ From the monorepo root:
143
+
144
+ ```bash
145
+ pnpm install
146
+ ```
147
+
148
+ This installs all workspace packages (`packages/*`, `app/frontend`, `app/backend`).
149
+
150
+ ## 6. The `rebase` CLI
151
+
152
+ The `rebase` command comes from the `@rebasepro/cli` package (`packages/cli`). After `pnpm install`, it is available via the workspace `node_modules/.bin/rebase` binary.
153
+
154
+ Run CLI commands from the **`app/`** directory (or monorepo root if configured):
155
+
156
+ ```bash
157
+ # From the app/ directory:
158
+ rebase schema generate # Generate Drizzle schema from collection definitions
159
+ rebase db push # Push schema directly to the database (dev workflow)
160
+ rebase dev # Start the dev server (frontend + backend)
161
+ rebase --help # Show all available commands
162
+ ```
163
+
164
+ ## 7. Initialize the Database
165
+
166
+ ```bash
167
+ rebase schema generate
168
+ rebase db push
169
+ ```
170
+
171
+ ## 8. Start the Development Server
172
+
173
+ ```bash
174
+ pnpm run dev
175
+ ```
176
+
177
+ This starts both:
178
+ - **Frontend** (Vite) at `http://localhost:5173`
179
+ - **Backend** (Hono) at `http://localhost:3001`
180
+
181
+ The frontend proxies API requests to the backend via `VITE_API_URL`.
182
+
183
+ ## References
184
+
185
+ - **Documentation:** [rebase.pro/docs](https://rebase.pro/docs)
186
+ - **GitHub:** [github.com/rebasepro/rebase](https://github.com/rebasepro/rebase)
187
+ - **Env reference:** `app/.env.example` (69 vars with inline documentation)
188
+ - **Env validation:** `packages/server-core/src/env.ts` (Zod schema + auto-generated secrets logic)
189
+ - **CLI source:** `packages/cli/src/cli.ts` (all commands and help text)
@@ -0,0 +1,3 @@
1
+ # References
2
+
3
+ Reference documentation for the rebase-local-env-setup skill. Add detailed reference files here.