@react-spa-scaffold/mcp 2.2.0 → 2.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 (138) hide show
  1. package/dist/constants.d.ts +4 -0
  2. package/dist/constants.d.ts.map +1 -1
  3. package/dist/constants.js +4 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/features/definitions/api.d.ts.map +1 -1
  6. package/dist/features/definitions/api.js +2 -1
  7. package/dist/features/definitions/api.js.map +1 -1
  8. package/dist/features/definitions/database.d.ts +3 -0
  9. package/dist/features/definitions/database.d.ts.map +1 -0
  10. package/dist/features/definitions/database.js +45 -0
  11. package/dist/features/definitions/database.js.map +1 -0
  12. package/dist/features/definitions/deployment.d.ts +3 -0
  13. package/dist/features/definitions/deployment.d.ts.map +1 -0
  14. package/dist/features/definitions/deployment.js +14 -0
  15. package/dist/features/definitions/deployment.js.map +1 -0
  16. package/dist/features/definitions/electron.d.ts +3 -0
  17. package/dist/features/definitions/electron.d.ts.map +1 -0
  18. package/dist/features/definitions/electron.js +23 -0
  19. package/dist/features/definitions/electron.js.map +1 -0
  20. package/dist/features/definitions/index.d.ts +3 -0
  21. package/dist/features/definitions/index.d.ts.map +1 -1
  22. package/dist/features/definitions/index.js +3 -0
  23. package/dist/features/definitions/index.js.map +1 -1
  24. package/dist/features/registry.d.ts.map +1 -1
  25. package/dist/features/registry.js +4 -1
  26. package/dist/features/registry.js.map +1 -1
  27. package/dist/features/types.d.ts +1 -0
  28. package/dist/features/types.d.ts.map +1 -1
  29. package/dist/features/types.test.js +5 -2
  30. package/dist/features/types.test.js.map +1 -1
  31. package/dist/resources/docs.d.ts.map +1 -1
  32. package/dist/resources/docs.js +5 -0
  33. package/dist/resources/docs.js.map +1 -1
  34. package/dist/tools/add-features.js +1 -1
  35. package/dist/tools/add-features.js.map +1 -1
  36. package/dist/tools/get-features.test.js +7 -0
  37. package/dist/tools/get-features.test.js.map +1 -1
  38. package/dist/tools/get-scaffold.d.ts +1 -0
  39. package/dist/tools/get-scaffold.d.ts.map +1 -1
  40. package/dist/tools/get-scaffold.js +4 -1
  41. package/dist/tools/get-scaffold.js.map +1 -1
  42. package/dist/tools/get-scaffold.test.js +50 -0
  43. package/dist/tools/get-scaffold.test.js.map +1 -1
  44. package/dist/utils/docs.d.ts.map +1 -1
  45. package/dist/utils/docs.js +2 -0
  46. package/dist/utils/docs.js.map +1 -1
  47. package/dist/utils/scaffold/claude-md/index.d.ts.map +1 -1
  48. package/dist/utils/scaffold/claude-md/index.js +4 -1
  49. package/dist/utils/scaffold/claude-md/index.js.map +1 -1
  50. package/dist/utils/scaffold/claude-md/sections.d.ts +3 -0
  51. package/dist/utils/scaffold/claude-md/sections.d.ts.map +1 -1
  52. package/dist/utils/scaffold/claude-md/sections.js +174 -2
  53. package/dist/utils/scaffold/claude-md/sections.js.map +1 -1
  54. package/dist/utils/scaffold/compute.d.ts.map +1 -1
  55. package/dist/utils/scaffold/compute.js +4 -2
  56. package/dist/utils/scaffold/compute.js.map +1 -1
  57. package/dist/utils/scaffold/generators.d.ts +7 -2
  58. package/dist/utils/scaffold/generators.d.ts.map +1 -1
  59. package/dist/utils/scaffold/generators.js +100 -22
  60. package/dist/utils/scaffold/generators.js.map +1 -1
  61. package/package.json +1 -1
  62. package/templates/.env.example +40 -12
  63. package/templates/.github/workflows/ci.yml +49 -2
  64. package/templates/.github/workflows/deploy.yml +46 -0
  65. package/templates/CLAUDE.md +180 -1
  66. package/templates/docs/AUTHENTICATION.md +325 -0
  67. package/templates/docs/DEPLOYMENT.md +296 -0
  68. package/templates/docs/E2E_TESTING.md +81 -4
  69. package/templates/docs/SUPABASE_INTEGRATION.md +310 -0
  70. package/templates/docs/TESTING.md +195 -77
  71. package/templates/e2e/auth/auth.setup.ts +60 -0
  72. package/templates/e2e/fixtures/index.ts +11 -0
  73. package/templates/e2e/tests/profile.auth.spec.ts +103 -0
  74. package/templates/e2e/tests/profile.spec.ts +64 -0
  75. package/templates/e2e/tests/register-form.spec.ts +38 -0
  76. package/templates/forge.config.js +53 -0
  77. package/templates/gitignore +5 -0
  78. package/templates/package.json +13 -1
  79. package/templates/playwright.config.ts +33 -3
  80. package/templates/src/App.tsx +32 -19
  81. package/templates/src/components/layout/Header.test.tsx +17 -1
  82. package/templates/src/components/layout/Header.tsx +11 -0
  83. package/templates/src/components/shared/AccountButton/AccountButton.test.tsx +3 -3
  84. package/templates/src/components/shared/ProfileSync/ProfileSync.test.tsx +44 -0
  85. package/templates/src/components/shared/ProfileSync/ProfileSync.tsx +104 -0
  86. package/templates/src/components/shared/ProfileSync/index.ts +1 -0
  87. package/templates/src/components/shared/ProtectedRoute/ProtectedRoute.test.tsx +3 -3
  88. package/templates/src/components/shared/index.ts +1 -0
  89. package/templates/src/contexts/performanceContext.tsx +3 -3
  90. package/templates/src/contexts/queryContext.tsx +9 -8
  91. package/templates/src/contexts/supabaseContext.test.tsx +59 -0
  92. package/templates/src/contexts/supabaseContext.tsx +87 -0
  93. package/templates/src/hooks/index.ts +17 -0
  94. package/templates/src/hooks/supabase/index.ts +12 -0
  95. package/templates/src/hooks/supabase/useProfiles.test.tsx +207 -0
  96. package/templates/src/hooks/supabase/useProfiles.ts +213 -0
  97. package/templates/src/hooks/supabase/useSupabaseQuery.test.tsx +150 -0
  98. package/templates/src/hooks/supabase/useSupabaseQuery.ts +91 -0
  99. package/templates/src/lib/api.test.ts +30 -38
  100. package/templates/src/lib/api.ts +1 -7
  101. package/templates/src/lib/config.ts +54 -4
  102. package/templates/src/lib/env.ts +36 -14
  103. package/templates/src/lib/index.ts +4 -2
  104. package/templates/src/lib/routes.ts +1 -0
  105. package/templates/src/lib/sentry.ts +13 -10
  106. package/templates/src/lib/supabase/client.ts +58 -0
  107. package/templates/src/lib/supabase/index.ts +5 -0
  108. package/templates/src/main.ts +227 -0
  109. package/templates/src/main.tsx +32 -42
  110. package/templates/src/mocks/constants.ts +31 -0
  111. package/templates/src/mocks/fixtures/index.ts +3 -1
  112. package/templates/src/mocks/fixtures/profiles.ts +55 -0
  113. package/templates/src/mocks/fixtures/users.ts +91 -0
  114. package/templates/src/mocks/handlers/index.ts +2 -1
  115. package/templates/src/mocks/handlers/supabase.ts +64 -0
  116. package/templates/src/mocks/handlers/todos.ts +1 -1
  117. package/templates/src/mocks/index.ts +6 -0
  118. package/templates/src/pages/Profile.test.tsx +263 -0
  119. package/templates/src/pages/Profile.tsx +171 -0
  120. package/templates/src/pages/index.ts +1 -0
  121. package/templates/src/preload.ts +26 -0
  122. package/templates/src/stores/preferencesStore.ts +2 -1
  123. package/templates/src/test/clerkMock.tsx +49 -9
  124. package/templates/src/test/fetchMock.ts +58 -0
  125. package/templates/src/test/index.ts +49 -3
  126. package/templates/src/test/mocks.ts +128 -1
  127. package/templates/src/test/providers.tsx +7 -4
  128. package/templates/src/test/supabaseMock.ts +112 -0
  129. package/templates/src/test-setup.ts +26 -0
  130. package/templates/src/types/database.ts +46 -0
  131. package/templates/src/types/global.d.ts +28 -0
  132. package/templates/src/types/index.ts +1 -0
  133. package/templates/src/types/supabase.ts +167 -0
  134. package/templates/src/vite-env.d.ts +6 -0
  135. package/templates/supabase/migrations/20260104000000_create_profiles_table.sql +67 -0
  136. package/templates/vite.main.config.mjs +20 -0
  137. package/templates/vite.preload.config.mjs +17 -0
  138. package/templates/vite.renderer.config.mjs +52 -0
@@ -1,19 +1,17 @@
1
- # Application
1
+ # ─────────────────────────────────────────────────────────────
2
+ # Application (required)
3
+ # ─────────────────────────────────────────────────────────────
2
4
  VITE_APP_NAME="My App"
3
5
  VITE_APP_URL=http://localhost:5173
4
-
5
- # Optional: Base URL for deployment subdirectory
6
- # VITE_BASE_URL=/
6
+ VITE_API_URL=https://jsonplaceholder.typicode.com
7
7
 
8
8
  # ─────────────────────────────────────────────────────────────
9
- # Sentry Error Tracking (production only)
9
+ # Sentry Error Tracking (required)
10
10
  # ─────────────────────────────────────────────────────────────
11
- # Set to 'false' to disable Sentry entirely (opt-out)
12
- # Enabled by default when DSN is provided
13
- # VITE_SENTRY_ENABLED=true
14
-
15
11
  # Runtime DSN for error reporting (client-side, safe to expose)
16
- # VITE_SENTRY_DSN=https://xxxxx@o123456.ingest.sentry.io/789
12
+ # Get from: https://sentry.io/settings/projects/YOUR_PROJECT/keys/
13
+ VITE_SENTRY_DSN=https://xxxxx@o123456.ingest.sentry.io/789
14
+ VITE_SENTRY_ENABLED=true
17
15
 
18
16
  # CI/CD secrets for source map upload (set in GitHub Secrets):
19
17
  # - SENTRY_AUTH_TOKEN: API token for uploading source maps
@@ -21,7 +19,37 @@ VITE_APP_URL=http://localhost:5173
21
19
  # - SENTRY_PROJECT: Sentry project slug
22
20
 
23
21
  # ─────────────────────────────────────────────────────────────
24
- # Clerk Authentication
22
+ # Clerk Authentication (required)
25
23
  # ─────────────────────────────────────────────────────────────
26
24
  # Get your Publishable Key from: https://dashboard.clerk.com/~/api-keys
27
- VITE_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
25
+ VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
26
+
27
+ # ─────────────────────────────────────────────────────────────
28
+ # Supabase Database (required)
29
+ # ─────────────────────────────────────────────────────────────
30
+ # Get your Project URL and API Key from:
31
+ # https://supabase.com/dashboard/project/YOUR_PROJECT/settings/api
32
+ #
33
+ # For Netlify deployments, these can be auto-configured via the
34
+ # Netlify Supabase extension: Extensions > Supabase > Connect
35
+ VITE_SUPABASE_DATABASE_URL=https://your-project.supabase.co
36
+ VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
37
+
38
+ # ─────────────────────────────────────────────────────────────
39
+ # Performance Testing (required)
40
+ # ─────────────────────────────────────────────────────────────
41
+ VITE_PERF_TEST=false
42
+
43
+ # Supabase CLI (required for npm run db:types)
44
+ # Project ID is the subdomain from your Supabase URL (e.g., abc123xyz from https://abc123xyz.supabase.co)
45
+ SUPABASE_PROJECT_ID=your-project-id
46
+
47
+ # ─────────────────────────────────────────────────────────────
48
+ # E2E Testing (optional - for authenticated Playwright tests)
49
+ # ─────────────────────────────────────────────────────────────
50
+ # Create a test user in Clerk and provide credentials here
51
+ # Required for running: npx playwright test --project=authenticated
52
+ # E2E_CLERK_USER_USERNAME=test@example.com
53
+ # E2E_CLERK_USER_PASSWORD=your-test-password
54
+ # CLERK_SECRET_KEY=sk_test_xxxxx
55
+
@@ -20,6 +20,7 @@ jobs:
20
20
  - uses: ./.github/actions/setup-node-deps
21
21
  - run: npm run lint
22
22
  - run: npm run format:check
23
+ - run: npm run sync:check
23
24
 
24
25
  typecheck:
25
26
  name: Type Check
@@ -41,7 +42,7 @@ jobs:
41
42
 
42
43
  build:
43
44
  name: Build
44
- needs: [lint, typecheck]
45
+ needs: [lint, typecheck, security]
45
46
  runs-on: ubuntu-latest
46
47
  timeout-minutes: 10
47
48
  steps:
@@ -96,7 +97,7 @@ jobs:
96
97
  upload-on: failure
97
98
  - type: performance
98
99
  project: performance
99
- command: PERF_TEST=true npx playwright test --project=performance
100
+ command: PERF_TEST=true PERF_CI=true npx playwright test --project=performance
100
101
  report-name: performance-report
101
102
  upload-on: always
102
103
  steps:
@@ -106,6 +107,9 @@ jobs:
106
107
  with:
107
108
  name: dist
108
109
  path: dist/
110
+ - name: Rebuild with performance tracking
111
+ if: matrix.type == 'performance'
112
+ run: VITE_PERF_TEST=true npm run build
109
113
  - name: Get Playwright version
110
114
  id: playwright-version
111
115
  run: echo "version=$(npm ls @playwright/test --json | jq -r '.dependencies["@playwright/test"].version')" >> $GITHUB_OUTPUT
@@ -131,3 +135,46 @@ jobs:
131
135
  name: ${{ matrix.report-name }}
132
136
  path: playwright-report/
133
137
  retention-days: ${{ matrix.type == 'performance' && 14 || 7 }}
138
+
139
+ deploy:
140
+ name: Deploy
141
+ needs: [build, test, test-e2e]
142
+ runs-on: ubuntu-latest
143
+ timeout-minutes: 10
144
+ permissions:
145
+ pull-requests: write
146
+ deployments: write
147
+ steps:
148
+ - uses: actions/download-artifact@v6
149
+ with:
150
+ name: dist
151
+ path: dist/
152
+
153
+ - name: Deploy Preview
154
+ if: github.event_name == 'pull_request'
155
+ uses: nwtgck/actions-netlify@v3
156
+ with:
157
+ publish-dir: './dist'
158
+ production-deploy: false
159
+ github-token: ${{ secrets.GITHUB_TOKEN }}
160
+ deploy-message: 'Preview deploy from PR #${{ github.event.number }}'
161
+ enable-pull-request-comment: true
162
+ enable-commit-comment: false
163
+ overwrites-pull-request-comment: true
164
+ alias: pr-${{ github.event.number }}
165
+ env:
166
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
167
+ NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
168
+
169
+ - name: Deploy Production
170
+ if: github.event_name == 'push'
171
+ uses: nwtgck/actions-netlify@v3
172
+ with:
173
+ publish-dir: './dist'
174
+ production-deploy: true
175
+ github-token: ${{ secrets.GITHUB_TOKEN }}
176
+ deploy-message: 'Production deploy from ${{ github.sha }}'
177
+ enable-commit-comment: true
178
+ env:
179
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
180
+ NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
@@ -0,0 +1,46 @@
1
+ name: Deploy (Manual)
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ environment:
7
+ description: 'Deploy environment'
8
+ required: true
9
+ default: 'preview'
10
+ type: choice
11
+ options:
12
+ - preview
13
+ - production
14
+
15
+ permissions:
16
+ contents: read
17
+ deployments: write
18
+
19
+ jobs:
20
+ deploy:
21
+ name: Deploy (${{ inputs.environment }})
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 15
24
+ steps:
25
+ - uses: actions/checkout@v6
26
+
27
+ - uses: ./.github/actions/setup-node-deps
28
+
29
+ - name: Build
30
+ run: npm run build
31
+ env:
32
+ SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
33
+ SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
34
+ SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
35
+
36
+ - name: Deploy
37
+ uses: nwtgck/actions-netlify@v3
38
+ with:
39
+ publish-dir: './dist'
40
+ production-deploy: ${{ inputs.environment == 'production' }}
41
+ github-token: ${{ secrets.GITHUB_TOKEN }}
42
+ deploy-message: 'Manual ${{ inputs.environment }} deploy from ${{ github.sha }}'
43
+ enable-commit-comment: ${{ inputs.environment == 'production' }}
44
+ env:
45
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
46
+ NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
@@ -19,6 +19,11 @@ npm run e2e:mobile # Playwright E2E (mobile)
19
19
  npm run e2e:all # Playwright E2E (all viewports)
20
20
  npm run e2e:perf # Performance regression tests
21
21
  npm run i18n:extract # Extract translations to .po
22
+ npm run db:types # Generate Supabase TypeScript types
23
+ npm run db:push # Push database migrations
24
+ npm run db:studio # Open Supabase Studio
25
+ npm run sync:check # Check monorepo dependency versions
26
+ npm run sync:fix # Auto-fix version mismatches
22
27
  ```
23
28
 
24
29
  ## Project Structure
@@ -213,10 +218,184 @@ import { render, mockMatchMedia, server } from '@/test';
213
218
 
214
219
  MSW handlers auto-reset after each test.
215
220
 
221
+ ## Authentication (Clerk)
222
+
223
+ When the auth feature is enabled, Clerk authentication is required.
224
+
225
+ ### Setup
226
+
227
+ 1. Create an account at [clerk.com](https://clerk.com)
228
+ 2. Get your Publishable Key from the dashboard
229
+ 3. Copy `.env.example` to `.env` and set your key:
230
+ ```
231
+ VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
232
+ ```
233
+
234
+ ### Usage
235
+
236
+ ```tsx
237
+ // Protect routes that require authentication
238
+ import { ProtectedRoute } from '@/components/shared';
239
+
240
+ <Route
241
+ path="/dashboard"
242
+ element={
243
+ <ProtectedRoute>
244
+ <DashboardPage />
245
+ </ProtectedRoute>
246
+ }
247
+ />;
248
+ ```
249
+
250
+ ```tsx
251
+ // Conditional rendering based on auth state
252
+ import { SignedIn, SignedOut, UserButton, SignInButton } from '@clerk/react-router';
253
+
254
+ <SignedIn>
255
+ <UserButton />
256
+ </SignedIn>
257
+ <SignedOut>
258
+ <SignInButton mode="modal">
259
+ <Button>Sign In</Button>
260
+ </SignInButton>
261
+ </SignedOut>
262
+ ```
263
+
264
+ ### Testing
265
+
266
+ Clerk is automatically mocked in tests. Use test utilities to control auth state:
267
+
268
+ ```tsx
269
+ import { setMockClerkSignedIn, resetClerkMocks } from '@/test';
270
+
271
+ beforeEach(() => resetClerkMocks());
272
+
273
+ it('shows sign-in when not authenticated', () => {
274
+ setMockClerkSignedIn(false);
275
+ // ...
276
+ });
277
+ ```
278
+
279
+ ## Database (Supabase)
280
+
281
+ Supabase provides PostgreSQL database with Row Level Security (RLS), integrated with Clerk authentication.
282
+
283
+ ### Setup
284
+
285
+ 1. Create a project at [supabase.com](https://supabase.com)
286
+ 2. Configure Clerk as third-party auth provider:
287
+ - Supabase Dashboard → Authentication → Providers → Third-Party Auth → Add Clerk
288
+ 3. Enable Supabase integration in Clerk:
289
+ - Clerk Dashboard → Integrations → Supabase → Activate
290
+ 4. Set environment variables in `.env`:
291
+ ```
292
+ VITE_SUPABASE_DATABASE_URL=https://your-project.supabase.co
293
+ VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
294
+ ```
295
+
296
+ ### Database Commands
297
+
298
+ ```bash
299
+ npm run db:types # Generate TypeScript types from schema
300
+ npm run db:push # Push migrations to database
301
+ npm run db:reset # Reset database (WARNING: destructive)
302
+ npm run db:studio # Open Supabase Studio
303
+ ```
304
+
305
+ ### Usage
306
+
307
+ ```tsx
308
+ import { useSupabase, useSupabaseQuery, useProfile } from '@/hooks';
309
+
310
+ // Direct client access
311
+ const supabase = useSupabase();
312
+ const { data } = await supabase.from('profiles').select();
313
+
314
+ // TanStack Query wrapper for automatic caching
315
+ const { data, isLoading } = useSupabaseQuery({
316
+ table: 'profiles',
317
+ queryKey: ['current'],
318
+ });
319
+
320
+ // Convenience hook for current user's profile
321
+ const { profile, isLoading, exists } = useProfile();
322
+ ```
323
+
324
+ ### Profile Mutations
325
+
326
+ ```tsx
327
+ import { useUpsertProfile, useUpdateProfile, useDeleteProfile } from '@/hooks';
328
+
329
+ // Create or update profile (upsert)
330
+ const upsertProfile = useUpsertProfile();
331
+ await upsertProfile.mutateAsync({ id: userId, email: 'user@example.com' });
332
+
333
+ // Update current user's profile
334
+ const updateProfile = useUpdateProfile();
335
+ await updateProfile.mutateAsync({ full_name: 'John' });
336
+
337
+ // Delete current user's profile
338
+ const deleteProfile = useDeleteProfile();
339
+ await deleteProfile.mutateAsync();
340
+ ```
341
+
342
+ ### Auto-Sync with ProfileSync
343
+
344
+ ```tsx
345
+ import { ProfileSync } from '@/components/shared';
346
+
347
+ // Add to your app to auto-sync Clerk user data to Supabase
348
+ function App() {
349
+ return (
350
+ <>
351
+ <ProfileSync />
352
+ <Routes>...</Routes>
353
+ </>
354
+ );
355
+ }
356
+ ```
357
+
358
+ ### Row Level Security (RLS)
359
+
360
+ All tables should have RLS enabled. Policies use `auth.uid()` which equals the Clerk user_id:
361
+
362
+ ```sql
363
+ -- Users can only access their own data
364
+ CREATE POLICY "Users can view own profile"
365
+ ON profiles FOR SELECT TO authenticated
366
+ USING (id = auth.uid());
367
+ ```
368
+
369
+ ### Testing
370
+
371
+ Supabase context is mocked in tests with state controls:
372
+
373
+ ```tsx
374
+ import { render, setMockSupabaseData, setMockSupabaseError, createProfile, resetSupabaseMocks } from '@/test';
375
+
376
+ beforeEach(() => resetSupabaseMocks());
377
+
378
+ it('displays profile data', async () => {
379
+ setMockSupabaseData([createProfile({ full_name: 'Test User' })]);
380
+ render(<ProfileCard />);
381
+ // Assert profile is displayed
382
+ });
383
+
384
+ it('handles error', async () => {
385
+ setMockSupabaseError({ message: 'Failed', code: 'ERROR' });
386
+ render(<ProfileCard />);
387
+ // Assert error state
388
+ });
389
+ ```
390
+
216
391
  ## Common Gotchas
217
392
 
218
393
  1. **Node.js >= 22.0.0** required (check `.nvmrc`)
219
394
  2. **Conventional commits** enforced by commitlint
220
- 3. **Context hooks throw** outside provider (e.g., `useMobileContext()`)
395
+ 3. **Context hooks throw** outside provider (e.g., `useMobileContext()`, `useSupabase()`)
221
396
  4. **Barrel exports** in each directory via `index.ts`
222
397
  5. **UI components** import directly: `@/components/ui/button` (no barrel)
398
+ 6. **Clerk auth required** when auth feature is enabled - set `VITE_CLERK_PUBLISHABLE_KEY` in `.env`
399
+ 7. **Supabase requires Clerk** - SupabaseProvider must be inside ClerkProvider
400
+ 8. **RLS policies required** - All Supabase tables should have Row Level Security enabled
401
+ 9. **Monorepo deps** - Run `npm run sync:check` to detect version mismatches across packages