create-claude-webapp 1.0.0 → 1.0.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 (79) hide show
  1. package/.claude/agents/acceptance-test-generator.md +256 -0
  2. package/.claude/agents/auth-flow-designer.md +93 -0
  3. package/.claude/agents/code-reviewer.md +193 -0
  4. package/.claude/agents/code-verifier.md +194 -0
  5. package/.claude/agents/deployment-executor.md +90 -0
  6. package/.claude/agents/design-sync.md +226 -0
  7. package/.claude/agents/document-reviewer.md +304 -0
  8. package/.claude/agents/environment-validator.md +100 -0
  9. package/.claude/agents/integration-test-reviewer.md +196 -0
  10. package/.claude/agents/investigator.md +162 -0
  11. package/.claude/agents/prd-creator.md +220 -0
  12. package/.claude/agents/quality-fixer-frontend.md +323 -0
  13. package/.claude/agents/quality-fixer.md +280 -0
  14. package/.claude/agents/requirement-analyzer.md +149 -0
  15. package/.claude/agents/rls-policy-designer.md +86 -0
  16. package/.claude/agents/rule-advisor.md +123 -0
  17. package/.claude/agents/scope-discoverer.md +231 -0
  18. package/.claude/agents/solver.md +173 -0
  19. package/.claude/agents/supabase-migration-generator.md +85 -0
  20. package/.claude/agents/task-decomposer.md +246 -0
  21. package/.claude/agents/task-executor-frontend.md +264 -0
  22. package/.claude/agents/task-executor.md +261 -0
  23. package/.claude/agents/technical-designer-frontend.md +444 -0
  24. package/.claude/agents/technical-designer.md +370 -0
  25. package/.claude/agents/verifier.md +193 -0
  26. package/.claude/agents/work-planner.md +211 -0
  27. package/.claude/commands/add-integration-tests.md +116 -0
  28. package/.claude/commands/build.md +77 -0
  29. package/.claude/commands/db-migrate.md +96 -0
  30. package/.claude/commands/deploy.md +95 -0
  31. package/.claude/commands/design.md +75 -0
  32. package/.claude/commands/diagnose.md +202 -0
  33. package/.claude/commands/front-build.md +116 -0
  34. package/.claude/commands/front-design.md +61 -0
  35. package/.claude/commands/front-plan.md +53 -0
  36. package/.claude/commands/front-reverse-design.md +183 -0
  37. package/.claude/commands/front-review.md +89 -0
  38. package/.claude/commands/implement.md +80 -0
  39. package/.claude/commands/local-dev.md +94 -0
  40. package/.claude/commands/plan.md +61 -0
  41. package/.claude/commands/project-inject.md +76 -0
  42. package/.claude/commands/refine-skill.md +207 -0
  43. package/.claude/commands/reverse-engineer.md +301 -0
  44. package/.claude/commands/review.md +88 -0
  45. package/.claude/commands/setup-auth.md +68 -0
  46. package/.claude/commands/setup-supabase.md +66 -0
  47. package/.claude/commands/setup-vercel.md +71 -0
  48. package/.claude/commands/sync-skills.md +116 -0
  49. package/.claude/commands/task.md +13 -0
  50. package/.claude/skills/coding-standards/SKILL.md +246 -0
  51. package/.claude/skills/documentation-criteria/SKILL.md +184 -0
  52. package/.claude/skills/documentation-criteria/references/adr-template.md +64 -0
  53. package/.claude/skills/documentation-criteria/references/design-template.md +263 -0
  54. package/.claude/skills/documentation-criteria/references/plan-template.md +130 -0
  55. package/.claude/skills/documentation-criteria/references/prd-template.md +109 -0
  56. package/.claude/skills/documentation-criteria/references/task-template.md +38 -0
  57. package/.claude/skills/frontend/technical-spec/SKILL.md +147 -0
  58. package/.claude/skills/frontend/typescript-rules/SKILL.md +136 -0
  59. package/.claude/skills/frontend/typescript-testing/SKILL.md +129 -0
  60. package/.claude/skills/fullstack-integration/SKILL.md +466 -0
  61. package/.claude/skills/implementation-approach/SKILL.md +141 -0
  62. package/.claude/skills/integration-e2e-testing/SKILL.md +146 -0
  63. package/.claude/skills/interview/SKILL.md +345 -0
  64. package/.claude/skills/project-context/SKILL.md +53 -0
  65. package/.claude/skills/stack-auth/SKILL.md +519 -0
  66. package/.claude/skills/subagents-orchestration-guide/SKILL.md +218 -0
  67. package/.claude/skills/supabase/SKILL.md +289 -0
  68. package/.claude/skills/supabase-edge-functions/SKILL.md +386 -0
  69. package/.claude/skills/supabase-local/SKILL.md +328 -0
  70. package/.claude/skills/supabase-testing/SKILL.md +513 -0
  71. package/.claude/skills/task-analyzer/SKILL.md +131 -0
  72. package/.claude/skills/task-analyzer/references/skills-index.yaml +375 -0
  73. package/.claude/skills/technical-spec/SKILL.md +86 -0
  74. package/.claude/skills/typescript-rules/SKILL.md +121 -0
  75. package/.claude/skills/typescript-testing/SKILL.md +155 -0
  76. package/.claude/skills/vercel-deployment/SKILL.md +355 -0
  77. package/.claude/skills/vercel-edge/SKILL.md +407 -0
  78. package/README.md +1 -1
  79. package/package.json +1 -1
@@ -0,0 +1,519 @@
1
+ ---
2
+ name: stack-auth
3
+ description: Stack-auth integration, MCP server usage, and authentication flows. Use when implementing authentication with Stack-auth.
4
+ ---
5
+
6
+ # Stack-auth Integration
7
+
8
+ ## Overview
9
+
10
+ Stack-auth is a modern authentication solution with an MCP server for AI-assisted development.
11
+
12
+ **MCP Server**: `https://mcp.stack-auth.com/`
13
+
14
+ ## Setup
15
+
16
+ ### Installation
17
+ ```bash
18
+ npm install @stackframe/stack
19
+ ```
20
+
21
+ ### Environment Variables
22
+ ```env
23
+ # Public (browser-accessible)
24
+ NEXT_PUBLIC_STACK_PROJECT_ID=your-project-id
25
+ NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=pk_...
26
+
27
+ # Server-only
28
+ STACK_SECRET_SERVER_KEY=sk_...
29
+ ```
30
+
31
+ ### Provider Setup
32
+ ```typescript
33
+ // app/layout.tsx
34
+ import { StackProvider, StackTheme } from '@stackframe/stack'
35
+ import { stackServerApp } from '@/lib/stack'
36
+
37
+ export default function RootLayout({
38
+ children,
39
+ }: {
40
+ children: React.ReactNode
41
+ }) {
42
+ return (
43
+ <html lang="en">
44
+ <body>
45
+ <StackProvider app={stackServerApp}>
46
+ <StackTheme>
47
+ {children}
48
+ </StackTheme>
49
+ </StackProvider>
50
+ </body>
51
+ </html>
52
+ )
53
+ }
54
+ ```
55
+
56
+ ### Stack Client Configuration
57
+ ```typescript
58
+ // lib/stack.ts
59
+ import { StackServerApp } from '@stackframe/stack'
60
+
61
+ export const stackServerApp = new StackServerApp({
62
+ projectId: process.env.NEXT_PUBLIC_STACK_PROJECT_ID!,
63
+ publishableClientKey: process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY!,
64
+ secretServerKey: process.env.STACK_SECRET_SERVER_KEY!,
65
+ })
66
+ ```
67
+
68
+ ## Authentication Flows
69
+
70
+ ### Email/Password Authentication
71
+ ```typescript
72
+ // components/auth/sign-in-form.tsx
73
+ 'use client'
74
+
75
+ import { useStackApp } from '@stackframe/stack'
76
+ import { useState } from 'react'
77
+
78
+ export function SignInForm() {
79
+ const app = useStackApp()
80
+ const [email, setEmail] = useState('')
81
+ const [password, setPassword] = useState('')
82
+ const [error, setError] = useState<string | null>(null)
83
+
84
+ const handleSubmit = async (e: React.FormEvent) => {
85
+ e.preventDefault()
86
+ setError(null)
87
+
88
+ try {
89
+ await app.signInWithCredential({
90
+ email,
91
+ password,
92
+ })
93
+ // Redirect handled automatically
94
+ } catch (err) {
95
+ setError(err instanceof Error ? err.message : 'Sign in failed')
96
+ }
97
+ }
98
+
99
+ return (
100
+ <form onSubmit={handleSubmit}>
101
+ <input
102
+ type="email"
103
+ value={email}
104
+ onChange={(e) => setEmail(e.target.value)}
105
+ placeholder="Email"
106
+ required
107
+ />
108
+ <input
109
+ type="password"
110
+ value={password}
111
+ onChange={(e) => setPassword(e.target.value)}
112
+ placeholder="Password"
113
+ required
114
+ />
115
+ {error && <p className="error">{error}</p>}
116
+ <button type="submit">Sign In</button>
117
+ </form>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ### OAuth Authentication
123
+ ```typescript
124
+ // components/auth/oauth-buttons.tsx
125
+ 'use client'
126
+
127
+ import { useStackApp } from '@stackframe/stack'
128
+
129
+ export function OAuthButtons() {
130
+ const app = useStackApp()
131
+
132
+ return (
133
+ <div className="oauth-buttons">
134
+ <button onClick={() => app.signInWithOAuth('google')}>
135
+ Continue with Google
136
+ </button>
137
+ <button onClick={() => app.signInWithOAuth('github')}>
138
+ Continue with GitHub
139
+ </button>
140
+ </div>
141
+ )
142
+ }
143
+ ```
144
+
145
+ ### Magic Link Authentication
146
+ ```typescript
147
+ // components/auth/magic-link-form.tsx
148
+ 'use client'
149
+
150
+ import { useStackApp } from '@stackframe/stack'
151
+ import { useState } from 'react'
152
+
153
+ export function MagicLinkForm() {
154
+ const app = useStackApp()
155
+ const [email, setEmail] = useState('')
156
+ const [sent, setSent] = useState(false)
157
+
158
+ const handleSubmit = async (e: React.FormEvent) => {
159
+ e.preventDefault()
160
+
161
+ await app.sendMagicLinkEmail(email)
162
+ setSent(true)
163
+ }
164
+
165
+ if (sent) {
166
+ return <p>Check your email for a sign-in link!</p>
167
+ }
168
+
169
+ return (
170
+ <form onSubmit={handleSubmit}>
171
+ <input
172
+ type="email"
173
+ value={email}
174
+ onChange={(e) => setEmail(e.target.value)}
175
+ placeholder="Email"
176
+ required
177
+ />
178
+ <button type="submit">Send Magic Link</button>
179
+ </form>
180
+ )
181
+ }
182
+ ```
183
+
184
+ ## User Management
185
+
186
+ ### Getting Current User
187
+ ```typescript
188
+ // Client component
189
+ 'use client'
190
+
191
+ import { useUser } from '@stackframe/stack'
192
+
193
+ export function UserProfile() {
194
+ const user = useUser()
195
+
196
+ if (!user) {
197
+ return <p>Not signed in</p>
198
+ }
199
+
200
+ return (
201
+ <div>
202
+ <p>Email: {user.primaryEmail}</p>
203
+ <p>Name: {user.displayName}</p>
204
+ <img src={user.profileImageUrl} alt="Profile" />
205
+ </div>
206
+ )
207
+ }
208
+ ```
209
+
210
+ ```typescript
211
+ // Server component
212
+ import { stackServerApp } from '@/lib/stack'
213
+
214
+ export default async function ProfilePage() {
215
+ const user = await stackServerApp.getUser()
216
+
217
+ if (!user) {
218
+ redirect('/sign-in')
219
+ }
220
+
221
+ return (
222
+ <div>
223
+ <h1>Welcome, {user.displayName}</h1>
224
+ </div>
225
+ )
226
+ }
227
+ ```
228
+
229
+ ### Updating User Profile
230
+ ```typescript
231
+ 'use client'
232
+
233
+ import { useUser } from '@stackframe/stack'
234
+
235
+ export function UpdateProfileForm() {
236
+ const user = useUser({ or: 'redirect' })
237
+
238
+ const handleUpdate = async (formData: FormData) => {
239
+ await user.update({
240
+ displayName: formData.get('name') as string,
241
+ })
242
+ }
243
+
244
+ return (
245
+ <form action={handleUpdate}>
246
+ <input
247
+ name="name"
248
+ defaultValue={user.displayName ?? ''}
249
+ placeholder="Display Name"
250
+ />
251
+ <button type="submit">Update</button>
252
+ </form>
253
+ )
254
+ }
255
+ ```
256
+
257
+ ## Security Best Practices
258
+
259
+ ### Session Configuration
260
+ ```typescript
261
+ // lib/stack.ts
262
+ export const stackServerApp = new StackServerApp({
263
+ // ... other config
264
+ tokenStore: 'cookie', // Use httpOnly cookies
265
+ })
266
+ ```
267
+
268
+ ### Protected Routes
269
+ ```typescript
270
+ // app/dashboard/page.tsx
271
+ import { stackServerApp } from '@/lib/stack'
272
+ import { redirect } from 'next/navigation'
273
+
274
+ export default async function DashboardPage() {
275
+ const user = await stackServerApp.getUser()
276
+
277
+ if (!user) {
278
+ redirect('/sign-in?redirect=/dashboard')
279
+ }
280
+
281
+ return <Dashboard user={user} />
282
+ }
283
+ ```
284
+
285
+ ### API Route Protection
286
+ ```typescript
287
+ // app/api/protected/route.ts
288
+ import { stackServerApp } from '@/lib/stack'
289
+ import { NextResponse } from 'next/server'
290
+
291
+ export async function GET() {
292
+ const user = await stackServerApp.getUser()
293
+
294
+ if (!user) {
295
+ return NextResponse.json(
296
+ { error: 'Unauthorized' },
297
+ { status: 401 }
298
+ )
299
+ }
300
+
301
+ return NextResponse.json({ user })
302
+ }
303
+ ```
304
+
305
+ ### Middleware Protection
306
+ ```typescript
307
+ // middleware.ts
308
+ import { NextResponse } from 'next/server'
309
+ import type { NextRequest } from 'next/server'
310
+
311
+ const protectedPaths = ['/dashboard', '/settings', '/api/protected']
312
+
313
+ export function middleware(request: NextRequest) {
314
+ const { pathname } = request.nextUrl
315
+
316
+ // Check if path needs protection
317
+ const isProtected = protectedPaths.some(path => pathname.startsWith(path))
318
+
319
+ if (!isProtected) {
320
+ return NextResponse.next()
321
+ }
322
+
323
+ // Check for Stack-auth session cookie
324
+ const sessionCookie = request.cookies.get('stack-session')
325
+
326
+ if (!sessionCookie) {
327
+ const signInUrl = new URL('/sign-in', request.url)
328
+ signInUrl.searchParams.set('redirect', pathname)
329
+ return NextResponse.redirect(signInUrl)
330
+ }
331
+
332
+ return NextResponse.next()
333
+ }
334
+
335
+ export const config = {
336
+ matcher: ['/dashboard/:path*', '/settings/:path*', '/api/protected/:path*'],
337
+ }
338
+ ```
339
+
340
+ ## Integration with Supabase
341
+
342
+ ### Syncing User ID
343
+ ```typescript
344
+ // After Stack-auth sign-in, sync with Supabase
345
+ import { stackServerApp } from '@/lib/stack'
346
+ import { supabaseAdmin } from '@/lib/supabase-admin'
347
+
348
+ export async function syncUserToSupabase() {
349
+ const stackUser = await stackServerApp.getUser()
350
+
351
+ if (!stackUser) return null
352
+
353
+ // Check if user exists in Supabase
354
+ const { data: existingUser } = await supabaseAdmin
355
+ .from('users')
356
+ .select('id')
357
+ .eq('stack_auth_id', stackUser.id)
358
+ .single()
359
+
360
+ if (!existingUser) {
361
+ // Create user in Supabase
362
+ const { data: newUser, error } = await supabaseAdmin
363
+ .from('users')
364
+ .insert({
365
+ stack_auth_id: stackUser.id,
366
+ email: stackUser.primaryEmail,
367
+ name: stackUser.displayName,
368
+ })
369
+ .select()
370
+ .single()
371
+
372
+ if (error) throw error
373
+ return newUser
374
+ }
375
+
376
+ return existingUser
377
+ }
378
+ ```
379
+
380
+ ### RLS with Stack-auth ID
381
+ ```sql
382
+ -- Migration: Add stack_auth_id to users table
383
+ ALTER TABLE users ADD COLUMN stack_auth_id TEXT UNIQUE;
384
+
385
+ -- Create index for lookups
386
+ CREATE INDEX idx_users_stack_auth_id ON users(stack_auth_id);
387
+
388
+ -- RLS policy using custom claim
389
+ CREATE POLICY "Users can access own data"
390
+ ON user_data FOR ALL
391
+ TO authenticated
392
+ USING (
393
+ user_id IN (
394
+ SELECT id FROM users
395
+ WHERE stack_auth_id = current_setting('app.stack_user_id', true)
396
+ )
397
+ );
398
+ ```
399
+
400
+ ### API Route with Both Auth Systems
401
+ ```typescript
402
+ // app/api/user-data/route.ts
403
+ import { stackServerApp } from '@/lib/stack'
404
+ import { createClient } from '@supabase/supabase-js'
405
+ import { NextResponse } from 'next/server'
406
+
407
+ export async function GET() {
408
+ // Get Stack-auth user
409
+ const stackUser = await stackServerApp.getUser()
410
+
411
+ if (!stackUser) {
412
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
413
+ }
414
+
415
+ // Create Supabase client with user context
416
+ const supabase = createClient(
417
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
418
+ process.env.SUPABASE_SERVICE_ROLE_KEY!
419
+ )
420
+
421
+ // Set user context for RLS
422
+ await supabase.rpc('set_config', {
423
+ setting: 'app.stack_user_id',
424
+ value: stackUser.id,
425
+ })
426
+
427
+ // Query with RLS
428
+ const { data, error } = await supabase
429
+ .from('user_data')
430
+ .select('*')
431
+
432
+ if (error) {
433
+ return NextResponse.json({ error: error.message }, { status: 500 })
434
+ }
435
+
436
+ return NextResponse.json({ data })
437
+ }
438
+ ```
439
+
440
+ ## MCP Server Usage
441
+
442
+ ### Configuring Claude Code MCP
443
+ Add to your Claude Code MCP configuration:
444
+
445
+ ```json
446
+ {
447
+ "mcpServers": {
448
+ "stack-auth": {
449
+ "url": "https://mcp.stack-auth.com/",
450
+ "transport": "sse"
451
+ }
452
+ }
453
+ }
454
+ ```
455
+
456
+ ### Available MCP Tools
457
+ The Stack-auth MCP server provides tools for:
458
+ - Creating and managing projects
459
+ - Configuring OAuth providers
460
+ - Managing users
461
+ - Generating authentication code
462
+
463
+ ## Sign Out
464
+
465
+ ```typescript
466
+ 'use client'
467
+
468
+ import { useStackApp } from '@stackframe/stack'
469
+
470
+ export function SignOutButton() {
471
+ const app = useStackApp()
472
+
473
+ return (
474
+ <button onClick={() => app.signOut()}>
475
+ Sign Out
476
+ </button>
477
+ )
478
+ }
479
+ ```
480
+
481
+ ## Error Handling
482
+
483
+ ```typescript
484
+ 'use client'
485
+
486
+ import { useStackApp } from '@stackframe/stack'
487
+ import { useState } from 'react'
488
+
489
+ export function AuthForm() {
490
+ const app = useStackApp()
491
+ const [error, setError] = useState<string | null>(null)
492
+
493
+ const handleAuth = async () => {
494
+ try {
495
+ await app.signInWithCredential({ email, password })
496
+ } catch (err) {
497
+ if (err instanceof Error) {
498
+ // Handle specific error types
499
+ if (err.message.includes('invalid_credentials')) {
500
+ setError('Invalid email or password')
501
+ } else if (err.message.includes('user_not_found')) {
502
+ setError('No account found with this email')
503
+ } else if (err.message.includes('email_not_verified')) {
504
+ setError('Please verify your email first')
505
+ } else {
506
+ setError('An error occurred. Please try again.')
507
+ }
508
+ }
509
+ }
510
+ }
511
+
512
+ return (
513
+ <div>
514
+ {error && <div className="error-banner">{error}</div>}
515
+ {/* Form fields */}
516
+ </div>
517
+ )
518
+ }
519
+ ```