@donotdev/cli 0.0.14 → 0.0.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.
Files changed (184) hide show
  1. package/dependencies-matrix.json +372 -88
  2. package/dist/bin/commands/agent-setup.js +7 -1
  3. package/dist/bin/commands/build.js +141 -44
  4. package/dist/bin/commands/bump.js +81 -41
  5. package/dist/bin/commands/cacheout.js +37 -9
  6. package/dist/bin/commands/create-app.js +276 -121
  7. package/dist/bin/commands/create-project.js +506 -217
  8. package/dist/bin/commands/deploy.js +1785 -694
  9. package/dist/bin/commands/dev.js +177 -43
  10. package/dist/bin/commands/doctor.d.ts +6 -0
  11. package/dist/bin/commands/doctor.d.ts.map +1 -0
  12. package/dist/bin/commands/{lint.js → doctor.js} +1215 -156
  13. package/dist/bin/commands/doctor.js.map +1 -0
  14. package/dist/bin/commands/emu.js +451 -104
  15. package/dist/bin/commands/format.js +37 -9
  16. package/dist/bin/commands/make-admin.js +77499 -11
  17. package/dist/bin/commands/preview.js +181 -43
  18. package/dist/bin/commands/setup.d.ts +6 -0
  19. package/dist/bin/commands/setup.d.ts.map +1 -0
  20. package/dist/bin/commands/setup.js +11733 -0
  21. package/dist/bin/commands/setup.js.map +1 -0
  22. package/dist/bin/commands/supabase-setup.d.ts +6 -0
  23. package/dist/bin/commands/supabase-setup.d.ts.map +1 -0
  24. package/dist/bin/commands/supabase-setup.js +7 -0
  25. package/dist/bin/commands/supabase-setup.js.map +1 -0
  26. package/dist/bin/commands/sync-secrets.js +211 -34
  27. package/dist/bin/commands/type-check.d.ts +14 -0
  28. package/dist/bin/commands/type-check.d.ts.map +1 -0
  29. package/dist/bin/commands/type-check.js +2049 -0
  30. package/dist/bin/commands/type-check.js.map +1 -0
  31. package/dist/bin/commands/wai.js +3 -1
  32. package/dist/bin/dndev.js +73 -52
  33. package/dist/bin/donotdev.js +54 -45
  34. package/dist/index.js +4212 -3050
  35. package/package.json +3 -3
  36. package/templates/app-demo/src/App.tsx.example +1 -0
  37. package/templates/app-demo/src/pages/FullPage.tsx.example +2 -2
  38. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +2 -2
  39. package/templates/app-demo/src/themes.css.example +5 -12
  40. package/templates/app-expo/.env.example +44 -0
  41. package/templates/app-expo/.expo/README.md.example +5 -0
  42. package/templates/app-expo/.gitignore.example +36 -0
  43. package/templates/app-expo/README.md.example +58 -0
  44. package/templates/app-expo/app/.gitkeep +2 -0
  45. package/templates/app-expo/app/_layout.tsx.example +41 -0
  46. package/templates/app-expo/app/form.tsx.example +52 -0
  47. package/templates/app-expo/app/index.tsx.example +89 -0
  48. package/templates/app-expo/app/list.tsx.example +32 -0
  49. package/templates/app-expo/app/profile.tsx.example +76 -0
  50. package/templates/app-expo/app/signin.tsx.example +53 -0
  51. package/templates/app-expo/app.json.example +39 -0
  52. package/templates/app-expo/assets/adaptive-icon.png +0 -0
  53. package/templates/app-expo/assets/favicon.png +0 -0
  54. package/templates/app-expo/assets/icon.png +0 -0
  55. package/templates/app-expo/assets/splash.png +0 -0
  56. package/templates/app-expo/babel.config.js.example +10 -0
  57. package/templates/app-expo/eas.json.example +20 -0
  58. package/templates/app-expo/expo-env.d.ts.example +4 -0
  59. package/templates/app-expo/metro.config.js.example +20 -0
  60. package/templates/app-expo/service-account-key.json.example +12 -0
  61. package/templates/app-expo/src/config/app.ts.example +46 -0
  62. package/templates/app-expo/src/config/providers.ts.example +7 -0
  63. package/templates/app-expo/tsconfig.json.example +19 -0
  64. package/templates/app-next/.env.example +4 -33
  65. package/templates/app-next/src/app/ClientLayout.tsx.example +2 -0
  66. package/templates/app-next/src/app/layout.tsx.example +7 -6
  67. package/templates/app-next/src/config/providers.ts.example +7 -0
  68. package/templates/app-next/src/globals.css.example +2 -11
  69. package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
  70. package/templates/app-next/src/themes.css.example +10 -13
  71. package/templates/app-vite/.env.example +3 -32
  72. package/templates/app-vite/index.html.example +2 -24
  73. package/templates/app-vite/src/App.tsx.example +2 -0
  74. package/templates/app-vite/src/config/providers.ts.example +7 -0
  75. package/templates/app-vite/src/globals.css.example +2 -12
  76. package/templates/app-vite/src/pages/FormPageExample.tsx.example +1 -2
  77. package/templates/app-vite/src/pages/HomePage.tsx.example +2 -2
  78. package/templates/app-vite/src/themes.css.example +109 -79
  79. package/templates/app-vite/vercel.json.example +11 -0
  80. package/templates/functions-firebase/README.md.example +1 -1
  81. package/templates/functions-firebase/build.mjs.example +2 -72
  82. package/templates/functions-firebase/functions-firebase/.env.example.example +24 -26
  83. package/templates/functions-firebase/functions-firebase/README.md.example +1 -1
  84. package/templates/functions-firebase/functions-firebase/build.mjs.example +2 -72
  85. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  86. package/templates/functions-firebase/functions.config.js.example +1 -1
  87. package/templates/functions-supabase/supabase/config.toml.example +59 -0
  88. package/templates/functions-supabase/supabase/functions/.env.example +13 -0
  89. package/templates/functions-supabase/supabase/functions/cancel-subscription/index.ts.example +7 -0
  90. package/templates/functions-supabase/supabase/functions/change-plan/index.ts.example +11 -0
  91. package/templates/functions-supabase/supabase/functions/create-checkout-session/index.ts.example +11 -0
  92. package/templates/functions-supabase/supabase/functions/create-customer-portal/index.ts.example +7 -0
  93. package/templates/functions-supabase/supabase/functions/crud/index.ts.example +16 -0
  94. package/templates/functions-supabase/supabase/functions/delete-account/index.ts.example +7 -0
  95. package/templates/functions-supabase/supabase/functions/deno.json.example +8 -0
  96. package/templates/functions-supabase/supabase/functions/get-custom-claims/index.ts.example +7 -0
  97. package/templates/functions-supabase/supabase/functions/get-user-auth-status/index.ts.example +7 -0
  98. package/templates/functions-supabase/supabase/functions/refresh-subscription-status/index.ts.example +7 -0
  99. package/templates/functions-supabase/supabase/functions/remove-custom-claims/index.ts.example +7 -0
  100. package/templates/functions-supabase/supabase/functions/set-custom-claims/index.ts.example +7 -0
  101. package/templates/functions-supabase/supabase/migrations/20250101000000_idempotency.sql +24 -0
  102. package/templates/functions-supabase/supabase/migrations/20250101000001_rate_limits.sql +22 -0
  103. package/templates/functions-supabase/supabase/migrations/20250101000002_cleanup_jobs.sql +28 -0
  104. package/templates/functions-supabase/supabase/migrations/20250101000003_operation_metrics.sql +28 -0
  105. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +1 -1
  106. package/templates/functions-vercel/functions-vercel/vercel.json.example +1 -1
  107. package/templates/functions-vercel/vercel.json.example +1 -1
  108. package/templates/github/github/workflows/firebase-deploy.yml.example +1 -1
  109. package/templates/github/workflows/firebase-deploy.yml.example +1 -1
  110. package/templates/overlay-firebase/env.fragment.example +34 -0
  111. package/templates/overlay-firebase/env.fragment.expo.example +34 -0
  112. package/templates/overlay-firebase/env.fragment.nextjs.example +34 -0
  113. package/templates/overlay-firebase/src/config/providers.expo.ts.example +49 -0
  114. package/templates/overlay-firebase/src/config/providers.ts.example +23 -0
  115. package/templates/overlay-supabase/env.fragment.example +12 -0
  116. package/templates/overlay-supabase/env.fragment.expo.example +12 -0
  117. package/templates/overlay-supabase/env.fragment.nextjs.example +12 -0
  118. package/templates/overlay-supabase/src/config/providers.expo.ts.example +35 -0
  119. package/templates/overlay-supabase/src/config/providers.ts.example +33 -0
  120. package/templates/overlay-supabase/vercel.headers.example +23 -0
  121. package/templates/overlay-supabase/vercel.json.example +22 -0
  122. package/templates/overlay-vercel/env.fragment.example +34 -0
  123. package/templates/overlay-vercel/env.fragment.nextjs.example +34 -0
  124. package/templates/overlay-vercel/src/config/providers.ts.example +24 -0
  125. package/templates/root-consumer/.claude/agents/architect.md.example +2 -310
  126. package/templates/root-consumer/.claude/agents/builder.md.example +2 -326
  127. package/templates/root-consumer/.claude/agents/coder.md.example +2 -83
  128. package/templates/root-consumer/.claude/agents/extractor.md.example +2 -231
  129. package/templates/root-consumer/.claude/agents/polisher.md.example +2 -132
  130. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +2 -81
  131. package/templates/root-consumer/.claude/commands/grill.md.example +30 -0
  132. package/templates/root-consumer/.claude/commands/techdebt.md.example +28 -0
  133. package/templates/root-consumer/.clinerules.example +1 -0
  134. package/templates/root-consumer/.cursor/rules/no-docs.mdc.example +15 -0
  135. package/templates/root-consumer/.cursorrules.example +1 -0
  136. package/templates/root-consumer/.github/copilot-instructions.md.example +1 -0
  137. package/templates/root-consumer/.windsurfrules.example +1 -0
  138. package/templates/root-consumer/AI.md.example +44 -123
  139. package/templates/root-consumer/CLAUDE.md.example +1 -134
  140. package/templates/root-consumer/CONVENTIONS.md.example +1 -0
  141. package/templates/root-consumer/GEMINI.md.example +1 -0
  142. package/templates/root-consumer/firebase.json.example +1 -1
  143. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +22 -2
  144. package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +0 -18
  145. package/templates/root-consumer/guides/dndev/COMPONENTS_UI.md.example +1 -1
  146. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +101 -32
  147. package/templates/root-consumer/guides/dndev/INDEX.md.example +4 -2
  148. package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
  149. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +241 -12
  150. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +13 -7
  151. package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +60 -0
  152. package/templates/root-consumer/guides/dndev/SETUP_SOC2.md.example +234 -0
  153. package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +62 -0
  154. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -0
  155. package/templates/root-consumer/guides/dndev/SETUP_THEMES.md.example +6 -2
  156. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +176 -0
  157. package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +5 -9
  158. package/templates/root-consumer/guides/dndev/essences_reference.css.example +174 -0
  159. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +7 -8
  160. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +10 -0
  161. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +25 -5
  162. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +13 -2
  163. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +2 -2
  164. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +55 -15
  165. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +15 -4
  166. package/templates/root-consumer/guides/wai-way/spec_template.md.example +7 -6
  167. package/dist/bin/commands/lint.d.ts +0 -11
  168. package/dist/bin/commands/lint.d.ts.map +0 -1
  169. package/dist/bin/commands/lint.js.map +0 -1
  170. package/dist/bin/commands/staging.d.ts +0 -11
  171. package/dist/bin/commands/staging.d.ts.map +0 -1
  172. package/dist/bin/commands/staging.js +0 -12
  173. package/dist/bin/commands/staging.js.map +0 -1
  174. package/templates/app-payload/.env.example +0 -28
  175. package/templates/app-payload/README.md.example +0 -233
  176. package/templates/app-payload/collections/Company.ts.example +0 -125
  177. package/templates/app-payload/collections/Hero.ts.example +0 -62
  178. package/templates/app-payload/collections/Media.ts.example +0 -41
  179. package/templates/app-payload/collections/Products.ts.example +0 -115
  180. package/templates/app-payload/collections/Services.ts.example +0 -104
  181. package/templates/app-payload/collections/Testimonials.ts.example +0 -92
  182. package/templates/app-payload/collections/Users.ts.example +0 -35
  183. package/templates/app-payload/src/server.ts.example +0 -79
  184. package/templates/app-payload/tsconfig.json.example +0 -24
@@ -0,0 +1,62 @@
1
+ # Stripe Setup Guide
2
+
3
+ ## Prerequisites
4
+ - Stripe account (https://dashboard.stripe.com)
5
+ - `@donotdev/billing` installed
6
+
7
+ ## 1. Get API Keys
8
+
9
+ 1. Go to https://dashboard.stripe.com/apikeys
10
+ 2. Copy your **Publishable key** (`pk_test_...`) → `.env`
11
+ 3. Copy your **Secret key** (`sk_test_...`) → `supabase/functions/.env` or `functions/.env`
12
+
13
+ > **Security:** Never commit secret keys. Stripe also supports restricted keys (`rk_test_...`, `rk_live_...`) for tighter permissions.
14
+
15
+ ## 2. Configure Webhook
16
+
17
+ 1. Go to https://dashboard.stripe.com/webhooks
18
+ 2. Click **Add endpoint**
19
+ 3. Set endpoint URL:
20
+ - Supabase: `https://{{PROJECT_ID}}.supabase.co/functions/v1/stripe-webhook`
21
+ - Firebase: `https://europe-west1-{{PROJECT_ID}}.cloudfunctions.net/stripeWebhook` (replace `europe-west1` with your region if different)
22
+ 4. Select events:
23
+ - `checkout.session.completed`
24
+ - `customer.subscription.created`
25
+ - `customer.subscription.updated`
26
+ - `customer.subscription.deleted`
27
+ - `invoice.payment_succeeded`
28
+ - `invoice.payment_failed`
29
+ 5. Copy the **Signing secret** (`whsec_...`) → `supabase/functions/.env`
30
+
31
+ ## 3. Environment Variables
32
+
33
+ ### App `.env` (public)
34
+ ```
35
+ VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
36
+ ```
37
+
38
+ ### Functions `.env` (secret)
39
+ ```
40
+ STRIPE_SECRET_KEY=sk_test_...
41
+ STRIPE_WEBHOOK_SECRET=whsec_...
42
+ ```
43
+
44
+ ## 4. Test Clocks (Optional)
45
+
46
+ For subscription testing without waiting for real billing cycles:
47
+ 1. Go to https://dashboard.stripe.com/test/test-clocks
48
+ 2. Create a test clock
49
+ 3. Create customers attached to the test clock
50
+ 4. Advance time to trigger billing events
51
+
52
+ ## 5. Verify
53
+
54
+ ```bash
55
+ dndev setup stripe # Interactive key setup + validation
56
+ dndev doctor # Health check for all providers
57
+ ```
58
+
59
+ Check that:
60
+ - Publishable key format is valid
61
+ - Secret key format is valid
62
+ - Key modes match (both test or both live)
@@ -0,0 +1,124 @@
1
+ # Setup: Supabase
2
+
3
+ **From zero to a working Supabase backend: env, tables, RLS, and adapter behavior.**
4
+
5
+ ---
6
+
7
+ ## Step 1: Run Supabase Setup
8
+
9
+ ```bash
10
+ dndev setup supabase
11
+ ```
12
+
13
+ This command:
14
+ - Lets you choose the target app (if you have an `apps/` directory)
15
+ - Asks for your **public** Supabase project URL and anon key
16
+ - Writes `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` to your app's `.env`
17
+
18
+ **We only ask for public credentials** (safe to ship in your client bundle). We never ask for the service_role key.
19
+
20
+ Get URL and anon key from: [Supabase Dashboard](https://supabase.com/dashboard) → your project → **Settings → API**.
21
+
22
+ ---
23
+
24
+ ## Step 2: Generate Tables from Entities
25
+
26
+ The framework can generate PostgreSQL migrations from your entity definitions (same source as the schema used by the app).
27
+
28
+ ```bash
29
+ dn generate sql
30
+ ```
31
+
32
+ **What it does:**
33
+ - Discovers entities (e.g. in `entities/` or your configured `--entity-dir`)
34
+ - For each entity: `CREATE TABLE` with columns mapped from field types (text, number, boolean, timestamptz, uuid, jsonb, etc.)
35
+ - Adds technical columns: `id` (uuid, default `gen_random_uuid()`), `user_id`, `created_at`, `updated_at` (with `DEFAULT now()`), `created_by_id`, `updated_by_id`, `status`
36
+ - Enables **Row Level Security (RLS)** and creates policies so rows are scoped by `auth.uid() = user_id`
37
+ - Adds a trigger so `updated_at` is set automatically on every `UPDATE`
38
+
39
+ **Options (optional):**
40
+ - `--entity-dir <path>` — where to find entity files (default: from app root)
41
+ - `--output-dir <path>` — where to write migrations (default: `supabase/migrations`)
42
+ - `--no-single-file` — one migration file per entity instead of one combined file
43
+
44
+ Output is written to `supabase/migrations/` (or your `--output-dir`) as a timestamped `.sql` file. Apply it with the Supabase CLI or Dashboard SQL editor.
45
+
46
+ ---
47
+
48
+ ## Step 3: Apply Migrations
49
+
50
+ After generating SQL:
51
+
52
+ **Option A — Supabase CLI (recommended)**
53
+
54
+ ```bash
55
+ supabase db push
56
+ ```
57
+
58
+ (or `supabase migration up` if you manage migrations locally)
59
+
60
+ **Option B — Dashboard**
61
+
62
+ Copy the contents of the generated migration file into the SQL Editor in the Supabase Dashboard and run it.
63
+
64
+ ---
65
+
66
+ ## Step 4: Adapter Behavior (DB-Managed Timestamps)
67
+
68
+ Tables use **snake_case** column names and **timestamptz** for `created_at` / `updated_at`. The framework expects **camelCase** and **ISO date strings** in the app.
69
+
70
+ The **Supabase CRUD adapter** handles this automatically:
71
+
72
+ | Direction | Behavior |
73
+ |-----------|----------|
74
+ | **Read** (get, query, subscribe) | Rows from Supabase are normalized: snake_case → camelCase (e.g. `created_at` → `createdAt`), and timestamp columns are converted to ISO strings. Your UI receives the same shape as with Firebase. |
75
+ | **Write** (add, set, update) | The adapter does **not** send `createdAt` / `updatedAt` (or snake equivalents). The database sets them via `DEFAULT now()` and the `updated_at` trigger. |
76
+
77
+ So you never set timestamps in app code when using Supabase — the DB owns them.
78
+
79
+ ---
80
+
81
+ ## Environment Variables
82
+
83
+ **Client (Vite):** in `apps/<app>/.env`
84
+
85
+ | Variable | Purpose |
86
+ |----------|---------|
87
+ | `VITE_SUPABASE_URL` | Project URL (public) |
88
+ | `VITE_SUPABASE_ANON_KEY` | Anon key (public, safe in bundle) |
89
+
90
+ **Server (e.g. API routes, Edge Functions):** use the same URL and `SUPABASE_SERVICE_ROLE_KEY` for admin operations. Never expose the service_role key to the client. Put it in `functions/.env` or your host’s env (Vercel, etc.).
91
+
92
+ See [ENV_SETUP.md](./ENV_SETUP.md) for where to put secrets.
93
+
94
+ ---
95
+
96
+ ## Storage (Optional)
97
+
98
+ If your app uploads files, create a storage bucket in the Supabase Dashboard (e.g. `uploads`). The default bucket name used by the framework is `uploads`. Configure public or RLS policies in the Dashboard as needed.
99
+
100
+ ---
101
+
102
+ ## Hosting the frontend
103
+
104
+ Supabase gives you **Auth, Postgres, Storage, and Edge Functions**. It does **not** host your built frontend (Vite/Next SPA). You need a separate host for the `dist/` output.
105
+
106
+ **We recommend:**
107
+
108
+ - **Vercel** — Connect your repo, set `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` in the project env, then deploy. Good fit for Next.js or Vite.
109
+ - We scaffold **vercel.json**; run `dndev deploy` and choose Frontend (Vercel) or Frontend + Edge Functions. Set `VITE_SUPABASE_*` in Vercel project env.
110
+
111
+ **Deploy:** Frontend goes to Vercel (scaffolded vercel.json); Edge Functions to Supabase. It does **not** deploy your Supabase app’s frontend to Vercel/Netlify. For that, use the host’s dashboard or CLI (e.g. `vercel`, `netlify deploy`) after building. See [ENV_SETUP.md](./ENV_SETUP.md) for production env vars on Vercel.
112
+
113
+ ---
114
+
115
+ ## Local Development
116
+
117
+ - **Against hosted Supabase:** After `dndev setup supabase`, run `bun dev` — the app talks to your Supabase project.
118
+ - **Local Supabase:** Install the [Supabase CLI](https://supabase.com/docs/guides/cli) and run `supabase start` for a local Postgres + Auth + Storage stack. Point `VITE_SUPABASE_URL` and keys to the local instance.
119
+
120
+ ---
121
+
122
+ ## Summary
123
+
124
+ **`dndev setup supabase`** → paste URL + anon key → **`dn generate sql`** → apply migrations → **`bun dev`**. The adapter normalizes read (snake→camel, ISO) and leaves timestamps to the DB on write.
@@ -1,12 +1,16 @@
1
1
  # Setup: Themes
2
2
 
3
- **Most is pre-configured.** Override CSS variables in `src/themes.css`. Framework handles theme switching, auto-computed colors.
3
+ **Single source of truth:** `src/themes.css`. Import it from `globals.css`; do not set font/color overrides in globals. Framework handles theme switching.
4
+
5
+ **Default essence = SaaS** (Inter, neutral). Optional essences (Brutalist, Luxury) are in the scaffold; they do **not** apply until you set the class on `<html>` (e.g. `class="brutalist"`) or use the theme switcher.
6
+
7
+ **Reference:** Copy Brutalist/Luxury blocks from `guides/dndev/essences_reference.css` into your `src/themes.css` if you need them. Default-essence fonts (Inter, Space Grotesk, Playfair, Roboto) are bundled via `@donotdev/ui`; no Google Fonts, no `public/fonts/` required.
4
8
 
5
9
  ---
6
10
 
7
11
  ## Standard Use
8
12
 
9
- **File:** `src/themes.css` (scaffolded with all variables)
13
+ **File:** `src/themes.css` (scaffolded with light, dark, and optional Brutalist/Luxury)
10
14
 
11
15
  **Override colors:**
12
16
  ```css
@@ -0,0 +1,176 @@
1
+ # Setup: Vercel
2
+
3
+ **From zero to deployed: Vercel hosting + API routes with Firebase data layer.**
4
+
5
+ ---
6
+
7
+ ## Architecture
8
+
9
+ Vercel is your **hosting and API platform** — it serves your frontend and runs serverless API routes.
10
+ Firebase is your **data layer** — Firestore (CRUD), Firebase Auth (users), Firebase Storage (files).
11
+
12
+ The framework generates API routes as Vercel Serverless Functions that talk to Firebase on the backend.
13
+
14
+ ---
15
+
16
+ ## Step 1: Create Firebase Project (Data Layer)
17
+
18
+ Even though you deploy to Vercel, you still need Firebase for data.
19
+
20
+ 1. Go to [Firebase Console](https://console.firebase.google.com) → Create a project
21
+ 2. Enable **Authentication** → Email/Password (+ OAuth providers if needed)
22
+ 3. Enable **Cloud Firestore** → Create Database → select region
23
+ 4. Enable **Storage** if your app uploads files
24
+
25
+ Get the Firebase web config from: **Project Settings → General → Your apps → Web app → SDK config**.
26
+
27
+ ---
28
+
29
+ ## Step 2: Run Setup
30
+
31
+ ```bash
32
+ dndev setup firebase
33
+ ```
34
+
35
+ This writes Firebase SDK config to your app's `.env`. The `overlay-vercel` providers.ts initializes the Firebase client SDK.
36
+
37
+ ---
38
+
39
+ ## Step 3: Configure Vercel
40
+
41
+ 1. Create a [Vercel](https://vercel.com) account and link your Git repo
42
+ 2. Import the project in Vercel Dashboard
43
+ 3. Set the **Root Directory** to `apps/<your-app>` (or leave blank if monorepo auto-detected)
44
+ 4. Set **Framework Preset** to Vite (or Next.js if using Next)
45
+
46
+ **Environment Variables** (in Vercel Dashboard → Settings → Environment Variables):
47
+
48
+ Copy your Firebase vars from `.env`:
49
+ - `VITE_FIREBASE_API_KEY`
50
+ - `VITE_FIREBASE_PROJECT_ID`
51
+ - `VITE_FIREBASE_AUTH_DOMAIN`
52
+ - `VITE_FIREBASE_STORAGE_BUCKET`
53
+ - `VITE_FIREBASE_MESSAGING_SENDER_ID`
54
+ - `VITE_FIREBASE_APP_ID`
55
+
56
+ For Next.js apps, use `NEXT_PUBLIC_` prefix instead of `VITE_`.
57
+
58
+ **Server secrets** (for API routes):
59
+ - `STRIPE_SECRET_KEY`
60
+ - `STRIPE_WEBHOOK_SECRET`
61
+ - Any OAuth client secrets
62
+
63
+ ---
64
+
65
+ ## Step 4: API Routes (Functions)
66
+
67
+ Your backend functions are in `functions/` and deploy as Vercel Serverless Functions.
68
+
69
+ ```
70
+ functions/
71
+ ├── src/
72
+ │ ├── auth/ # Auth endpoints (signup, login, etc.)
73
+ │ ├── billing/ # Stripe endpoints (checkout, webhook, etc.)
74
+ │ ├── crud/ # CRUD endpoints (create, read, update, delete)
75
+ │ └── oauth/ # OAuth callback handlers
76
+ ├── vercel.json # Route configuration
77
+ ├── tsconfig.json
78
+ └── package.json
79
+ ```
80
+
81
+ Functions use the Firebase Admin SDK on the server side to access Firestore, verify auth tokens, etc.
82
+
83
+ ---
84
+
85
+ ## Step 5: Deploy
86
+
87
+ **Option A — Git push (recommended)**
88
+
89
+ Push to your connected branch. Vercel auto-deploys.
90
+
91
+ ```bash
92
+ git push origin main
93
+ ```
94
+
95
+ **Option B — Vercel CLI**
96
+
97
+ ```bash
98
+ npx vercel --prod
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Environment Variables
104
+
105
+ | File | What Goes Here | Loaded By |
106
+ |------|---------------|-----------|
107
+ | `apps/<app>/.env` | Firebase config, license key, Stripe publishable key | Vite/Next.js (dev + build) |
108
+ | `apps/<app>/.env.local` | Local overrides (gitignored) | Vite/Next.js (overrides .env) |
109
+ | `apps/<app>/.env.production` | Production overrides | Vite/Next.js (build --mode production) |
110
+ | `functions/.env` | Server secrets: STRIPE_SECRET_KEY, OAuth secrets | API routes runtime |
111
+ | Vercel Dashboard | All production env vars (client + server) | Vercel runtime |
112
+
113
+ **Client vars** (browser-safe): `VITE_*` or `NEXT_PUBLIC_*` prefix.
114
+ **Server vars** (secrets): No prefix needed in Vercel Dashboard — only accessible in API routes.
115
+
116
+ ---
117
+
118
+ ## Local Development
119
+
120
+ ```bash
121
+ bun dev
122
+ ```
123
+
124
+ The app runs locally, talking to your Firebase project. API routes can be tested with:
125
+
126
+ ```bash
127
+ vercel dev
128
+ ```
129
+
130
+ Or use Firebase emulators for fully local development:
131
+
132
+ ```bash
133
+ dndev emu start
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Secrets
139
+
140
+ Server-side secrets go in `functions/.env` locally and in Vercel Dashboard for production.
141
+
142
+ **We NEVER ask for secret keys.** You place them yourself:
143
+
144
+ ```bash
145
+ # functions/.env
146
+ STRIPE_SECRET_KEY=sk_live_...
147
+ STRIPE_WEBHOOK_SECRET=whsec_...
148
+ ```
149
+
150
+ Then add the same values in Vercel Dashboard → Settings → Environment Variables.
151
+
152
+ See [ENV_SETUP.md → Secrets Philosophy](./ENV_SETUP.md#secrets-philosophy) for the full policy.
153
+
154
+ ---
155
+
156
+ ## Troubleshooting
157
+
158
+ **"Firebase config not loading"**
159
+ → Check `.env` is in your **app directory** (`apps/<app>/.env`), not repo root
160
+ → Vite vars must start with `VITE_`, Next.js vars with `NEXT_PUBLIC_`
161
+
162
+ **"401 / Permission denied on API routes"**
163
+ → Check Firebase service account key is configured in Vercel env vars
164
+ → Verify `GOOGLE_APPLICATION_CREDENTIALS` or inline credentials in API routes
165
+
166
+ **"CORS error"**
167
+ → Vercel handles CORS for same-origin requests automatically
168
+ → For cross-origin: add CORS headers in your API route handler
169
+
170
+ **"Build fails on Vercel"**
171
+ → Check Root Directory is set to your app directory
172
+ → Ensure `package.json` has correct `build` script
173
+
174
+ ---
175
+
176
+ **`dndev setup firebase` → configure Vercel project → set env vars → `git push`. Vercel deploys automatically.**
@@ -226,18 +226,14 @@ navigate('/products', {
226
226
 
227
227
  ### 5. Query Parameters
228
228
 
229
- **✅ Use framework useSearchParams:**
229
+ **✅ Use framework useSearchParams (read-only, returns URLSearchParams directly):**
230
230
  ```tsx
231
231
  import { useSearchParams } from '@donotdev/ui/routing';
232
232
 
233
233
  function ProductList() {
234
- const [searchParams, setSearchParams] = useSearchParams();
234
+ const searchParams = useSearchParams();
235
235
  const page = searchParams.get('page') || '1';
236
-
237
- const handlePageChange = (newPage: string) => {
238
- setSearchParams({ page: newPage });
239
- };
240
-
236
+
241
237
  return <div>Page: {page}</div>;
242
238
  }
243
239
  ```
@@ -478,8 +474,8 @@ navigate('/products', { replace: true });
478
474
  // Route params
479
475
  const id = useRouteParam('id');
480
476
 
481
- // Query params
482
- const [searchParams, setSearchParams] = useSearchParams();
477
+ // Query params (read-only, returns URLSearchParams directly)
478
+ const searchParams = useSearchParams();
483
479
  const page = searchParams.get('page');
484
480
 
485
481
  // Navigation menu
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Reference: Framework essences (Brutalist, Luxury).
3
+ * Copy the blocks you need into your app's src/themes.css.
4
+ * Default essence = SaaS (Inter); these do not apply until you set the class on <html>.
5
+ *
6
+ * Fonts: Space Grotesk (Brutalist), Playfair Display (Luxury), Inter, Roboto are bundled in @donotdev/ui (no external requests).
7
+ */
8
+
9
+ /** =========================================================================
10
+ * Brutalist — Industrial, monospace body, Space Grotesk headlines, orange/black.
11
+ * Set <html class="brutalist"> to apply.
12
+ * ========================================================================= */
13
+ .brutalist {
14
+ --theme-icon: 'Construction';
15
+ --theme-label: 'Brutalist';
16
+ --theme-is-dark: 1;
17
+
18
+ /* 1. Core Colors - Black + white + industrial orange */
19
+ --background: #000000;
20
+ --foreground: #ffffff;
21
+ --primary: #f97316;
22
+ --secondary: #ffffff;
23
+ --accent: #f97316;
24
+
25
+ /* 2. Semantic */
26
+ --success: #22c55e;
27
+ --warning: #f97316;
28
+ --destructive: #dc2626;
29
+
30
+ /* 3. Surfaces - Dark, industrial */
31
+ --muted: #111111;
32
+ --muted-foreground: #888888;
33
+ --border: #ffffff;
34
+ --input: #111111;
35
+ --ring: #f97316;
36
+ --card: #000000;
37
+ --card-foreground: #f97316;
38
+ --popover: #000000;
39
+ --popover-foreground: #ffffff;
40
+ --surface-1: #0a0a0a;
41
+
42
+ /* 4. Text on Colors */
43
+ --primary-foreground: #ffffff;
44
+ --secondary-foreground: #000000;
45
+ --accent-foreground: #000000;
46
+ --success-foreground: #ffffff;
47
+ --warning-foreground: #000000;
48
+ --destructive-foreground: #ffffff;
49
+
50
+ /* 5. Radius - Hard zero */
51
+ --radius-interactive: 0;
52
+ --radius-surface: 0;
53
+ --radius-floating: 0;
54
+
55
+ /* 6. Typography - Monospace for body, Space Grotesk 700 for headings */
56
+ --font-family: var(--font-mono);
57
+ --font-headline: "Space Grotesk", var(--font-sans);
58
+ --font-weight-semibold: 700;
59
+ --font-weight-bold: 700;
60
+
61
+ /* 7. Borders */
62
+ --border-width: 2px;
63
+ --border-huge: 4px;
64
+
65
+ /* 8. Shadows — flat by default, hard offset on interactive */
66
+ --shadow-color: var(--foreground);
67
+ --shadow-sm: none;
68
+ --shadow-md: none;
69
+ --shadow-xl: 8px 8px 0px 0px var(--shadow-color);
70
+ --shadow-cta: 20px 20px 0px 0px var(--shadow-color);
71
+
72
+ /* 9. Per-variant shadows — only at xl level (elevated/clickable) */
73
+ --shadow-primary: none;
74
+ --shadow-primary-xl: 8px 8px 0px 0px var(--background);
75
+ --shadow-secondary: none;
76
+ --shadow-secondary-xl: 8px 8px 0px 0px var(--primary);
77
+
78
+ /* 10. Header padding for hard-offset shadows */
79
+ --header-shadow-padding: 0.75rem;
80
+ }
81
+
82
+ /* Body - grid background */
83
+ .brutalist body {
84
+ background-color: var(--background);
85
+ background-image:
86
+ linear-gradient(#111 1px, transparent 1px),
87
+ linear-gradient(90deg, #111 1px, transparent 1px);
88
+ background-size: 40px 40px;
89
+ }
90
+
91
+ /* Uppercase headings (both native elements and Text component levels) */
92
+ .brutalist {
93
+ :is(h1, h2, h3, h4, h5, h6),
94
+ [data-level^='h'] {
95
+ text-transform: uppercase;
96
+ }
97
+ }
98
+
99
+ /* Flat surface - no gradient glow */
100
+ .brutalist .dndev-surface { background: var(--card); }
101
+ .brutalist .dndev-surface[data-variant='outline'] { border: var(--border-width) solid var(--border); }
102
+
103
+ .brutalist .dndev-card[data-variant='outline'] {
104
+ background: transparent;
105
+ box-shadow: none;
106
+ }
107
+
108
+
109
+ /** =========================================================================
110
+ * Luxury — Playfair Display headlines, gold/cream, warm shadows.
111
+ * Set <html class="luxury"> to apply.
112
+ * ========================================================================= */
113
+ .luxury {
114
+ --theme-icon: 'Gem';
115
+ --theme-label: 'Luxury';
116
+ --theme-is-dark: 0;
117
+
118
+ /* 1. Core Colors */
119
+ --background: #faf8f5;
120
+ --foreground: #1c1917;
121
+ --primary: #b45309;
122
+ --secondary: #fef3c7;
123
+ --accent: #92400e;
124
+
125
+ /* 2. Semantic */
126
+ --success: #15803d;
127
+ --warning: #b45309;
128
+ --destructive: #b91c1c;
129
+
130
+ /* 3. Surfaces */
131
+ --muted: #fef9c3;
132
+ --muted-foreground: #78716c;
133
+ --border: #e7e5e4;
134
+ --border-hairline: 1px;
135
+ --input: #ffffff;
136
+ --ring: #b45309;
137
+ --card: #ffffff;
138
+ --card-foreground: #1c1917;
139
+ --popover: #ffffff;
140
+ --popover-foreground: #1c1917;
141
+ --surface-1: #faf8f5;
142
+
143
+ /* 4. Text on Colors */
144
+ --primary-foreground: #ffffff;
145
+ --secondary-foreground: #1c1917;
146
+ --accent-foreground: #ffffff;
147
+ --success-foreground: #ffffff;
148
+ --warning-foreground: #1c1917;
149
+ --destructive-foreground: #ffffff;
150
+
151
+ /* 5. Radius */
152
+ --radius-interactive: 0.375rem;
153
+ --radius-surface: 0.5rem;
154
+ --radius-floating: 0.5rem;
155
+
156
+ /* 6. Typography — lighter weights, serif headlines */
157
+ --font-family: var(--font-sans);
158
+ --font-headline: 'Playfair Display', var(--font-serif);
159
+ --font-weight-normal: 300;
160
+ --font-weight-medium: 400;
161
+ --font-weight-semibold: 500;
162
+ --font-weight-bold: 600;
163
+
164
+ /* 7. Spacing — generous, one notch above expressive */
165
+ --gap-sm: 0.75rem;
166
+ --gap-md: 1.5rem;
167
+ --gap-lg: 3rem;
168
+
169
+ /* 8. Shadows — warm gold-tinted, soft diffused */
170
+ --shadow-color: color-mix(in oklab, #b45309 8%, transparent);
171
+ --shadow-sm: 0 1px 3px var(--shadow-color);
172
+ --shadow-md: 0 4px 12px var(--shadow-color);
173
+ --shadow-xl: 0 8px 24px var(--shadow-color);
174
+ }
@@ -168,18 +168,17 @@ Present completed spec summary:
168
168
  **READ:**
169
169
  - `guides/wai-way/page_patterns.md` - Page structure patterns
170
170
 
171
- ```bash
172
- # Create new app
173
- dndev create-app my-app --preset [from spec]
171
+ **`dndev` is an installed CLI — run directly, never via `bunx` or `npx`.**
174
172
 
175
- # Install dependencies
176
- cd my-app && bun install
173
+ ```bash
174
+ # Create new app (interactive wizard — no --preset flag, it prompts you)
175
+ dndev create-app
177
176
 
178
- # Start emulators
177
+ # Start emulators (if Firebase backend was selected)
179
178
  dndev emu start
180
179
 
181
- # Verify it runs
182
- bun dev
180
+ # Start the dev server
181
+ dndev dev
183
182
  ```
184
183
 
185
184
  ### Step 1.1: Create Page Files
@@ -31,6 +31,10 @@ core_principles:
31
31
  - HARDCODE strings first - validate UX before i18n
32
32
  - Use framework components only - no custom CSS
33
33
  - Trust component defaults
34
+ - **70/30 Hierarchy:** Use `primary` variant for the North Star action; `outline`/`ghost` for others.
35
+ - **Benefit-First Copy:** For Heros/Cards, translate technical features into outcomes (e.g., 'Optimize Your Fleet' vs 'Manage Cars').
36
+ - **Success Intent:** Trust framework defaults for CRUD (automatic toasts/loaders). Only propose custom redirects or celebratory components for the 'North Star' action or if the user asks for more polish.
37
+ - **Spec Drift:** If you must deviate from the spec (field types, logic), log it in `spec_changes.md`. Do NOT modify `spec_template.md` directly.
34
38
 
35
39
  crud_pattern:
36
40
  list_page: |
@@ -83,5 +87,11 @@ Rules:
83
87
  3. HARDCODE all strings (no i18n yet)
84
88
  4. Use framework components only
85
89
 
90
+ **Apply UX Mandates:**
91
+ - **Visual Anchor:** Every page must have ONE clear primary focus (Hero or Main Card).
92
+ - **Mobile First:** Ensure all touch targets are > 44px.
93
+ - **Kano Filter:** Use 'Benefit' copy for marketing/dashboard pages. Use 'Utility' copy for forms.
94
+ - **Success Intent:** Trust framework defaults. Only propose custom redirects/celebration for the 'North Star' action.
95
+
86
96
  Build each page following the scaffolded patterns.
87
97
  ```