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.
- package/.claude/agents/acceptance-test-generator.md +256 -0
- package/.claude/agents/auth-flow-designer.md +93 -0
- package/.claude/agents/code-reviewer.md +193 -0
- package/.claude/agents/code-verifier.md +194 -0
- package/.claude/agents/deployment-executor.md +90 -0
- package/.claude/agents/design-sync.md +226 -0
- package/.claude/agents/document-reviewer.md +304 -0
- package/.claude/agents/environment-validator.md +100 -0
- package/.claude/agents/integration-test-reviewer.md +196 -0
- package/.claude/agents/investigator.md +162 -0
- package/.claude/agents/prd-creator.md +220 -0
- package/.claude/agents/quality-fixer-frontend.md +323 -0
- package/.claude/agents/quality-fixer.md +280 -0
- package/.claude/agents/requirement-analyzer.md +149 -0
- package/.claude/agents/rls-policy-designer.md +86 -0
- package/.claude/agents/rule-advisor.md +123 -0
- package/.claude/agents/scope-discoverer.md +231 -0
- package/.claude/agents/solver.md +173 -0
- package/.claude/agents/supabase-migration-generator.md +85 -0
- package/.claude/agents/task-decomposer.md +246 -0
- package/.claude/agents/task-executor-frontend.md +264 -0
- package/.claude/agents/task-executor.md +261 -0
- package/.claude/agents/technical-designer-frontend.md +444 -0
- package/.claude/agents/technical-designer.md +370 -0
- package/.claude/agents/verifier.md +193 -0
- package/.claude/agents/work-planner.md +211 -0
- package/.claude/commands/add-integration-tests.md +116 -0
- package/.claude/commands/build.md +77 -0
- package/.claude/commands/db-migrate.md +96 -0
- package/.claude/commands/deploy.md +95 -0
- package/.claude/commands/design.md +75 -0
- package/.claude/commands/diagnose.md +202 -0
- package/.claude/commands/front-build.md +116 -0
- package/.claude/commands/front-design.md +61 -0
- package/.claude/commands/front-plan.md +53 -0
- package/.claude/commands/front-reverse-design.md +183 -0
- package/.claude/commands/front-review.md +89 -0
- package/.claude/commands/implement.md +80 -0
- package/.claude/commands/local-dev.md +94 -0
- package/.claude/commands/plan.md +61 -0
- package/.claude/commands/project-inject.md +76 -0
- package/.claude/commands/refine-skill.md +207 -0
- package/.claude/commands/reverse-engineer.md +301 -0
- package/.claude/commands/review.md +88 -0
- package/.claude/commands/setup-auth.md +68 -0
- package/.claude/commands/setup-supabase.md +66 -0
- package/.claude/commands/setup-vercel.md +71 -0
- package/.claude/commands/sync-skills.md +116 -0
- package/.claude/commands/task.md +13 -0
- package/.claude/skills/coding-standards/SKILL.md +246 -0
- package/.claude/skills/documentation-criteria/SKILL.md +184 -0
- package/.claude/skills/documentation-criteria/references/adr-template.md +64 -0
- package/.claude/skills/documentation-criteria/references/design-template.md +263 -0
- package/.claude/skills/documentation-criteria/references/plan-template.md +130 -0
- package/.claude/skills/documentation-criteria/references/prd-template.md +109 -0
- package/.claude/skills/documentation-criteria/references/task-template.md +38 -0
- package/.claude/skills/frontend/technical-spec/SKILL.md +147 -0
- package/.claude/skills/frontend/typescript-rules/SKILL.md +136 -0
- package/.claude/skills/frontend/typescript-testing/SKILL.md +129 -0
- package/.claude/skills/fullstack-integration/SKILL.md +466 -0
- package/.claude/skills/implementation-approach/SKILL.md +141 -0
- package/.claude/skills/integration-e2e-testing/SKILL.md +146 -0
- package/.claude/skills/interview/SKILL.md +345 -0
- package/.claude/skills/project-context/SKILL.md +53 -0
- package/.claude/skills/stack-auth/SKILL.md +519 -0
- package/.claude/skills/subagents-orchestration-guide/SKILL.md +218 -0
- package/.claude/skills/supabase/SKILL.md +289 -0
- package/.claude/skills/supabase-edge-functions/SKILL.md +386 -0
- package/.claude/skills/supabase-local/SKILL.md +328 -0
- package/.claude/skills/supabase-testing/SKILL.md +513 -0
- package/.claude/skills/task-analyzer/SKILL.md +131 -0
- package/.claude/skills/task-analyzer/references/skills-index.yaml +375 -0
- package/.claude/skills/technical-spec/SKILL.md +86 -0
- package/.claude/skills/typescript-rules/SKILL.md +121 -0
- package/.claude/skills/typescript-testing/SKILL.md +155 -0
- package/.claude/skills/vercel-deployment/SKILL.md +355 -0
- package/.claude/skills/vercel-edge/SKILL.md +407 -0
- package/README.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fullstack-integration
|
|
3
|
+
description: Cross-service integration patterns for Supabase, Vercel, and Stack-auth. Use when designing full-stack architecture or connecting services.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fullstack Integration
|
|
7
|
+
|
|
8
|
+
## Architecture Overview
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
12
|
+
│ Client (Browser) │
|
|
13
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ Vercel Edge (Middleware) │
|
|
18
|
+
│ • Route protection │
|
|
19
|
+
│ • Geo-routing │
|
|
20
|
+
│ • Rate limiting │
|
|
21
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
22
|
+
│
|
|
23
|
+
┌─────────────┴─────────────┐
|
|
24
|
+
▼ ▼
|
|
25
|
+
┌──────────────────────────────┐ ┌──────────────────────────────┐
|
|
26
|
+
│ Stack-auth │ │ Supabase │
|
|
27
|
+
│ • User authentication │ │ • PostgreSQL database │
|
|
28
|
+
│ • Session management │ │ • Row Level Security │
|
|
29
|
+
│ • OAuth providers │ │ • Realtime subscriptions │
|
|
30
|
+
│ • User profiles │ │ • Edge Functions │
|
|
31
|
+
└──────────────────────────────┘ └──────────────────────────────┘
|
|
32
|
+
│ │
|
|
33
|
+
└─────────────┬─────────────┘
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ Vercel Serverless Functions │
|
|
38
|
+
│ • Business logic │
|
|
39
|
+
│ • Auth verification │
|
|
40
|
+
│ • Database operations │
|
|
41
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Authentication Flow Integration
|
|
45
|
+
|
|
46
|
+
### Complete Sign-In Flow
|
|
47
|
+
```typescript
|
|
48
|
+
// 1. User signs in with Stack-auth
|
|
49
|
+
// 2. Get Stack-auth user ID
|
|
50
|
+
// 3. Sync/lookup user in Supabase
|
|
51
|
+
// 4. Use Supabase with user context
|
|
52
|
+
|
|
53
|
+
// lib/auth-integration.ts
|
|
54
|
+
import { stackServerApp } from '@/lib/stack'
|
|
55
|
+
import { createClient } from '@supabase/supabase-js'
|
|
56
|
+
import type { Database } from '@/types/database.types'
|
|
57
|
+
|
|
58
|
+
const supabaseAdmin = createClient<Database>(
|
|
59
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
60
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
export async function getAuthenticatedContext() {
|
|
64
|
+
// Get Stack-auth user
|
|
65
|
+
const stackUser = await stackServerApp.getUser()
|
|
66
|
+
|
|
67
|
+
if (!stackUser) {
|
|
68
|
+
return { user: null, supabaseUserId: null }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Get or create Supabase user
|
|
72
|
+
let { data: supabaseUser } = await supabaseAdmin
|
|
73
|
+
.from('users')
|
|
74
|
+
.select('id')
|
|
75
|
+
.eq('stack_auth_id', stackUser.id)
|
|
76
|
+
.single()
|
|
77
|
+
|
|
78
|
+
if (!supabaseUser) {
|
|
79
|
+
const { data: newUser, error } = await supabaseAdmin
|
|
80
|
+
.from('users')
|
|
81
|
+
.insert({
|
|
82
|
+
stack_auth_id: stackUser.id,
|
|
83
|
+
email: stackUser.primaryEmail,
|
|
84
|
+
display_name: stackUser.displayName,
|
|
85
|
+
avatar_url: stackUser.profileImageUrl,
|
|
86
|
+
})
|
|
87
|
+
.select('id')
|
|
88
|
+
.single()
|
|
89
|
+
|
|
90
|
+
if (error) throw error
|
|
91
|
+
supabaseUser = newUser
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
user: stackUser,
|
|
96
|
+
supabaseUserId: supabaseUser.id,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Protected API Route Pattern
|
|
102
|
+
```typescript
|
|
103
|
+
// app/api/data/route.ts
|
|
104
|
+
import { NextResponse } from 'next/server'
|
|
105
|
+
import { getAuthenticatedContext } from '@/lib/auth-integration'
|
|
106
|
+
import { createSupabaseWithUserContext } from '@/lib/supabase'
|
|
107
|
+
|
|
108
|
+
export async function GET() {
|
|
109
|
+
const { user, supabaseUserId } = await getAuthenticatedContext()
|
|
110
|
+
|
|
111
|
+
if (!user || !supabaseUserId) {
|
|
112
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Create Supabase client with user context for RLS
|
|
116
|
+
const supabase = createSupabaseWithUserContext(supabaseUserId)
|
|
117
|
+
|
|
118
|
+
const { data, error } = await supabase
|
|
119
|
+
.from('user_data')
|
|
120
|
+
.select('*')
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
return NextResponse.json({ error: error.message }, { status: 500 })
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return NextResponse.json({ data })
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Environment Configuration
|
|
131
|
+
|
|
132
|
+
### Development (.env.local)
|
|
133
|
+
```env
|
|
134
|
+
# Stack-auth
|
|
135
|
+
NEXT_PUBLIC_STACK_PROJECT_ID=dev-project
|
|
136
|
+
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=pk_test_...
|
|
137
|
+
STACK_SECRET_SERVER_KEY=sk_test_...
|
|
138
|
+
|
|
139
|
+
# Supabase (local)
|
|
140
|
+
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
|
141
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...local...
|
|
142
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJ...local...
|
|
143
|
+
|
|
144
|
+
# App
|
|
145
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Production (Vercel Environment Variables)
|
|
149
|
+
```env
|
|
150
|
+
# Stack-auth
|
|
151
|
+
NEXT_PUBLIC_STACK_PROJECT_ID=prod-project
|
|
152
|
+
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=pk_live_...
|
|
153
|
+
STACK_SECRET_SERVER_KEY=sk_live_...
|
|
154
|
+
|
|
155
|
+
# Supabase (cloud)
|
|
156
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
157
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
|
|
158
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJ...
|
|
159
|
+
|
|
160
|
+
# App
|
|
161
|
+
NEXT_PUBLIC_APP_URL=https://your-app.vercel.app
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Environment Validation
|
|
165
|
+
```typescript
|
|
166
|
+
// lib/env.ts
|
|
167
|
+
const requiredEnvVars = [
|
|
168
|
+
'NEXT_PUBLIC_STACK_PROJECT_ID',
|
|
169
|
+
'NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY',
|
|
170
|
+
'STACK_SECRET_SERVER_KEY',
|
|
171
|
+
'NEXT_PUBLIC_SUPABASE_URL',
|
|
172
|
+
'NEXT_PUBLIC_SUPABASE_ANON_KEY',
|
|
173
|
+
'SUPABASE_SERVICE_ROLE_KEY',
|
|
174
|
+
] as const
|
|
175
|
+
|
|
176
|
+
export function validateEnv() {
|
|
177
|
+
const missing = requiredEnvVars.filter(
|
|
178
|
+
(key) => !process.env[key]
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if (missing.length > 0) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Missing required environment variables: ${missing.join(', ')}`
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Call at app startup
|
|
189
|
+
// app/layout.tsx or next.config.js
|
|
190
|
+
validateEnv()
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Error Handling Patterns
|
|
194
|
+
|
|
195
|
+
### Unified Error Response
|
|
196
|
+
```typescript
|
|
197
|
+
// lib/errors.ts
|
|
198
|
+
export class AppError extends Error {
|
|
199
|
+
constructor(
|
|
200
|
+
message: string,
|
|
201
|
+
public statusCode: number = 500,
|
|
202
|
+
public code?: string
|
|
203
|
+
) {
|
|
204
|
+
super(message)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export class UnauthorizedError extends AppError {
|
|
209
|
+
constructor(message = 'Unauthorized') {
|
|
210
|
+
super(message, 401, 'UNAUTHORIZED')
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export class NotFoundError extends AppError {
|
|
215
|
+
constructor(message = 'Not found') {
|
|
216
|
+
super(message, 404, 'NOT_FOUND')
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// API error handler
|
|
221
|
+
export function handleApiError(error: unknown) {
|
|
222
|
+
console.error('API Error:', error)
|
|
223
|
+
|
|
224
|
+
if (error instanceof AppError) {
|
|
225
|
+
return NextResponse.json(
|
|
226
|
+
{ error: error.message, code: error.code },
|
|
227
|
+
{ status: error.statusCode }
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (error instanceof Error) {
|
|
232
|
+
// Don't leak internal error details
|
|
233
|
+
return NextResponse.json(
|
|
234
|
+
{ error: 'Internal server error' },
|
|
235
|
+
{ status: 500 }
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return NextResponse.json(
|
|
240
|
+
{ error: 'Unknown error' },
|
|
241
|
+
{ status: 500 }
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Error Boundary Pattern
|
|
247
|
+
```typescript
|
|
248
|
+
// components/error-boundary.tsx
|
|
249
|
+
'use client'
|
|
250
|
+
|
|
251
|
+
import { useEffect } from 'react'
|
|
252
|
+
|
|
253
|
+
export function ErrorBoundary({
|
|
254
|
+
error,
|
|
255
|
+
reset,
|
|
256
|
+
}: {
|
|
257
|
+
error: Error & { digest?: string }
|
|
258
|
+
reset: () => void
|
|
259
|
+
}) {
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
// Log to error reporting service
|
|
262
|
+
console.error('Error boundary caught:', error)
|
|
263
|
+
}, [error])
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<div className="error-container">
|
|
267
|
+
<h2>Something went wrong!</h2>
|
|
268
|
+
<button onClick={reset}>Try again</button>
|
|
269
|
+
</div>
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Performance Patterns
|
|
275
|
+
|
|
276
|
+
### Parallel Data Fetching
|
|
277
|
+
```typescript
|
|
278
|
+
// app/dashboard/page.tsx
|
|
279
|
+
import { getAuthenticatedContext } from '@/lib/auth-integration'
|
|
280
|
+
import { supabaseAdmin } from '@/lib/supabase-admin'
|
|
281
|
+
|
|
282
|
+
export default async function DashboardPage() {
|
|
283
|
+
const { user, supabaseUserId } = await getAuthenticatedContext()
|
|
284
|
+
|
|
285
|
+
if (!user || !supabaseUserId) {
|
|
286
|
+
redirect('/sign-in')
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Fetch data in parallel
|
|
290
|
+
const [userStats, recentPosts, notifications] = await Promise.all([
|
|
291
|
+
supabaseAdmin
|
|
292
|
+
.from('user_stats')
|
|
293
|
+
.select('*')
|
|
294
|
+
.eq('user_id', supabaseUserId)
|
|
295
|
+
.single(),
|
|
296
|
+
supabaseAdmin
|
|
297
|
+
.from('posts')
|
|
298
|
+
.select('id, title, created_at')
|
|
299
|
+
.eq('user_id', supabaseUserId)
|
|
300
|
+
.order('created_at', { ascending: false })
|
|
301
|
+
.limit(5),
|
|
302
|
+
supabaseAdmin
|
|
303
|
+
.from('notifications')
|
|
304
|
+
.select('*')
|
|
305
|
+
.eq('user_id', supabaseUserId)
|
|
306
|
+
.eq('read', false)
|
|
307
|
+
.limit(10),
|
|
308
|
+
])
|
|
309
|
+
|
|
310
|
+
return (
|
|
311
|
+
<Dashboard
|
|
312
|
+
stats={userStats.data}
|
|
313
|
+
recentPosts={recentPosts.data}
|
|
314
|
+
notifications={notifications.data}
|
|
315
|
+
/>
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Caching Strategy
|
|
321
|
+
```typescript
|
|
322
|
+
// lib/cache.ts
|
|
323
|
+
import { unstable_cache } from 'next/cache'
|
|
324
|
+
|
|
325
|
+
export const getCachedUserStats = unstable_cache(
|
|
326
|
+
async (userId: string) => {
|
|
327
|
+
const { data } = await supabaseAdmin
|
|
328
|
+
.from('user_stats')
|
|
329
|
+
.select('*')
|
|
330
|
+
.eq('user_id', userId)
|
|
331
|
+
.single()
|
|
332
|
+
|
|
333
|
+
return data
|
|
334
|
+
},
|
|
335
|
+
['user-stats'],
|
|
336
|
+
{
|
|
337
|
+
revalidate: 60, // Revalidate every minute
|
|
338
|
+
tags: ['user-stats'],
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
// Invalidate cache
|
|
343
|
+
import { revalidateTag } from 'next/cache'
|
|
344
|
+
revalidateTag('user-stats')
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Optimistic Updates
|
|
348
|
+
```typescript
|
|
349
|
+
// hooks/use-optimistic-mutation.ts
|
|
350
|
+
'use client'
|
|
351
|
+
|
|
352
|
+
import { useState, useTransition } from 'react'
|
|
353
|
+
|
|
354
|
+
export function useOptimisticMutation<T>(
|
|
355
|
+
currentData: T,
|
|
356
|
+
mutationFn: (newData: T) => Promise<T>
|
|
357
|
+
) {
|
|
358
|
+
const [optimisticData, setOptimisticData] = useState(currentData)
|
|
359
|
+
const [isPending, startTransition] = useTransition()
|
|
360
|
+
|
|
361
|
+
const mutate = async (newData: T) => {
|
|
362
|
+
// Optimistically update
|
|
363
|
+
setOptimisticData(newData)
|
|
364
|
+
|
|
365
|
+
startTransition(async () => {
|
|
366
|
+
try {
|
|
367
|
+
const result = await mutationFn(newData)
|
|
368
|
+
setOptimisticData(result)
|
|
369
|
+
} catch (error) {
|
|
370
|
+
// Revert on error
|
|
371
|
+
setOptimisticData(currentData)
|
|
372
|
+
throw error
|
|
373
|
+
}
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return { data: optimisticData, mutate, isPending }
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Database Schema Pattern
|
|
382
|
+
|
|
383
|
+
### Users Table with Stack-auth Integration
|
|
384
|
+
```sql
|
|
385
|
+
-- supabase/migrations/20240101000000_create_users.sql
|
|
386
|
+
|
|
387
|
+
CREATE TABLE public.users (
|
|
388
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
389
|
+
stack_auth_id TEXT UNIQUE NOT NULL,
|
|
390
|
+
email TEXT UNIQUE NOT NULL,
|
|
391
|
+
display_name TEXT,
|
|
392
|
+
avatar_url TEXT,
|
|
393
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
394
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
-- Enable RLS
|
|
398
|
+
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
|
|
399
|
+
|
|
400
|
+
-- Index for Stack-auth lookups
|
|
401
|
+
CREATE INDEX idx_users_stack_auth_id ON public.users(stack_auth_id);
|
|
402
|
+
|
|
403
|
+
-- Trigger for updated_at
|
|
404
|
+
CREATE TRIGGER update_users_updated_at
|
|
405
|
+
BEFORE UPDATE ON public.users
|
|
406
|
+
FOR EACH ROW
|
|
407
|
+
EXECUTE FUNCTION update_updated_at();
|
|
408
|
+
|
|
409
|
+
-- RLS Policies
|
|
410
|
+
CREATE POLICY "Users can view own profile"
|
|
411
|
+
ON public.users FOR SELECT
|
|
412
|
+
USING (stack_auth_id = current_setting('app.stack_auth_id', true));
|
|
413
|
+
|
|
414
|
+
CREATE POLICY "Users can update own profile"
|
|
415
|
+
ON public.users FOR UPDATE
|
|
416
|
+
USING (stack_auth_id = current_setting('app.stack_auth_id', true))
|
|
417
|
+
WITH CHECK (stack_auth_id = current_setting('app.stack_auth_id', true));
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Setting User Context for RLS
|
|
421
|
+
```typescript
|
|
422
|
+
// lib/supabase.ts
|
|
423
|
+
import { createClient } from '@supabase/supabase-js'
|
|
424
|
+
import type { Database } from '@/types/database.types'
|
|
425
|
+
|
|
426
|
+
export function createSupabaseWithUserContext(stackAuthId: string) {
|
|
427
|
+
const supabase = createClient<Database>(
|
|
428
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
429
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
// Set user context for RLS
|
|
433
|
+
supabase.rpc('set_config', {
|
|
434
|
+
setting: 'app.stack_auth_id',
|
|
435
|
+
value: stackAuthId,
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
return supabase
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Deployment Checklist
|
|
443
|
+
|
|
444
|
+
### Pre-Deployment
|
|
445
|
+
- [ ] All environment variables set in Vercel
|
|
446
|
+
- [ ] Supabase migrations applied to production
|
|
447
|
+
- [ ] Stack-auth production project configured
|
|
448
|
+
- [ ] OAuth redirect URLs updated for production domain
|
|
449
|
+
- [ ] RLS policies tested
|
|
450
|
+
|
|
451
|
+
### Post-Deployment
|
|
452
|
+
- [ ] Verify authentication flow works
|
|
453
|
+
- [ ] Test protected routes
|
|
454
|
+
- [ ] Verify Supabase connections
|
|
455
|
+
- [ ] Check error logging
|
|
456
|
+
- [ ] Monitor initial traffic
|
|
457
|
+
|
|
458
|
+
## Common Integration Issues
|
|
459
|
+
|
|
460
|
+
| Issue | Cause | Solution |
|
|
461
|
+
|-------|-------|----------|
|
|
462
|
+
| CORS errors | Missing headers | Configure CORS in Supabase and Vercel |
|
|
463
|
+
| Auth not persisting | Cookie settings | Check sameSite and secure flags |
|
|
464
|
+
| RLS blocking queries | Missing user context | Set `app.stack_auth_id` before queries |
|
|
465
|
+
| Type mismatches | Outdated types | Regenerate Supabase types |
|
|
466
|
+
| Slow queries | Missing indexes | Add indexes for foreign keys |
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implementation-approach
|
|
3
|
+
description: Selects implementation strategy (vertical slice, horizontal, or hybrid) with risk assessment. Use when planning feature implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Implementation Strategy Selection Framework (Meta-cognitive Approach)
|
|
7
|
+
|
|
8
|
+
## Meta-cognitive Strategy Selection Process
|
|
9
|
+
|
|
10
|
+
### Phase 1: Comprehensive Current State Analysis
|
|
11
|
+
|
|
12
|
+
**Core Question**: "What does the existing implementation look like?"
|
|
13
|
+
|
|
14
|
+
#### Analysis Framework
|
|
15
|
+
```yaml
|
|
16
|
+
Architecture Analysis: Responsibility separation, data flow, dependencies, technical debt
|
|
17
|
+
Implementation Quality Assessment: Code quality, test coverage, performance, security
|
|
18
|
+
Historical Context Understanding: Current form rationale, past decision validity, constraint changes, requirement evolution
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
#### Meta-cognitive Question List
|
|
22
|
+
- What is the true responsibility of this implementation?
|
|
23
|
+
- Which parts are business essence and which derive from technical constraints?
|
|
24
|
+
- What dependencies or implicit preconditions are unclear from the code?
|
|
25
|
+
- What benefits and constraints does the current design bring?
|
|
26
|
+
|
|
27
|
+
### Phase 2: Strategy Exploration and Creation
|
|
28
|
+
|
|
29
|
+
**Core Question**: "When determining before -> after, what implementation patterns or strategies should be referenced?"
|
|
30
|
+
|
|
31
|
+
#### Strategy Discovery Process
|
|
32
|
+
```yaml
|
|
33
|
+
Research and Exploration: Tech stack examples (WebSearch), similar projects, OSS references, literature/blogs
|
|
34
|
+
Creative Thinking: Strategy combinations, constraint-based design, phase division, extension point design
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### Reference Strategy Patterns (Creative Combinations Encouraged)
|
|
38
|
+
|
|
39
|
+
**Legacy Handling Strategies**:
|
|
40
|
+
- Strangler Pattern: Gradual migration through phased replacement
|
|
41
|
+
- Facade Pattern: Complexity hiding through unified interface
|
|
42
|
+
- Adapter Pattern: Bridge with existing systems
|
|
43
|
+
|
|
44
|
+
**New Development Strategies**:
|
|
45
|
+
- Feature-driven Development: Vertical implementation prioritizing user value
|
|
46
|
+
- Foundation-driven Development: Foundation-first construction prioritizing stability
|
|
47
|
+
- Risk-driven Development: Prioritize addressing maximum risk elements
|
|
48
|
+
|
|
49
|
+
**Integration/Migration Strategies**:
|
|
50
|
+
- Proxy Pattern: Transparent feature extension
|
|
51
|
+
- Decorator Pattern: Phased enhancement of existing features
|
|
52
|
+
- Bridge Pattern: Flexibility through abstraction
|
|
53
|
+
|
|
54
|
+
**Important**: The optimal solution is discovered through creative thinking according to each project's context.
|
|
55
|
+
|
|
56
|
+
### Phase 3: Risk Assessment and Control
|
|
57
|
+
|
|
58
|
+
**Core Question**: "What risks arise when applying this to existing implementation, and what's the best way to control them?"
|
|
59
|
+
|
|
60
|
+
#### Risk Analysis Matrix
|
|
61
|
+
```yaml
|
|
62
|
+
Technical Risks: System impact, data consistency, performance degradation, integration complexity
|
|
63
|
+
Operational Risks: Service availability, deployment downtime, process changes, rollback procedures
|
|
64
|
+
Project Risks: Schedule delays, learning costs, quality achievement, team coordination
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### Risk Control Strategies
|
|
68
|
+
```yaml
|
|
69
|
+
Preventive Measures: Phased migration, parallel operation verification, integration/regression tests, monitoring setup
|
|
70
|
+
Incident Response: Rollback procedures, log/metrics preparation, communication system, service continuation procedures
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Phase 4: Constraint Compatibility Verification
|
|
74
|
+
|
|
75
|
+
**Core Question**: "What are this project's constraints?"
|
|
76
|
+
|
|
77
|
+
#### Constraint Checklist
|
|
78
|
+
```yaml
|
|
79
|
+
Technical Constraints: Library compatibility, resource capacity, mandatory requirements, numerical targets
|
|
80
|
+
Temporal Constraints: Deadlines/priorities, dependencies, milestones, learning periods
|
|
81
|
+
Resource Constraints: Team/skills, work hours/systems, budget, external contracts
|
|
82
|
+
Business Constraints: Market launch timing, customer impact, regulatory compliance
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Phase 5: Implementation Approach Decision
|
|
86
|
+
|
|
87
|
+
Select optimal solution from basic implementation approaches (creative combinations encouraged):
|
|
88
|
+
|
|
89
|
+
#### Vertical Slice (Feature-driven)
|
|
90
|
+
**Characteristics**: Vertical implementation across all layers by feature unit
|
|
91
|
+
**Application Conditions**: Low inter-feature dependencies, output in user-usable form, changes needed across all architecture layers
|
|
92
|
+
**Verification Method**: End-user value delivery at each feature completion
|
|
93
|
+
|
|
94
|
+
#### Horizontal Slice (Foundation-driven)
|
|
95
|
+
**Characteristics**: Phased construction by architecture layer
|
|
96
|
+
**Application Conditions**: Foundation system stability important, multiple features depend on common foundation, layer-by-layer verification effective
|
|
97
|
+
**Verification Method**: Integrated operation verification when all foundation layers complete
|
|
98
|
+
|
|
99
|
+
#### Hybrid (Creative Combination)
|
|
100
|
+
**Characteristics**: Flexible combination according to project characteristics
|
|
101
|
+
**Application Conditions**: Unclear requirements, need to change approach per phase, transition from prototyping to full implementation
|
|
102
|
+
**Verification Method**: Verify at appropriate L1/L2/L3 levels according to each phase's goals
|
|
103
|
+
|
|
104
|
+
### Phase 6: Decision Rationale Documentation
|
|
105
|
+
|
|
106
|
+
**Design Doc Documentation**: Clearly specify implementation strategy selection reasons and rationale.
|
|
107
|
+
|
|
108
|
+
## Verification Level Definitions
|
|
109
|
+
|
|
110
|
+
Priority for completion verification of each task:
|
|
111
|
+
|
|
112
|
+
- **L1: Functional Operation Verification** - Operates as end-user feature (e.g., search executable)
|
|
113
|
+
- **L2: Test Operation Verification** - New tests added and passing (e.g., type definition tests)
|
|
114
|
+
- **L3: Build Success Verification** - No compile errors (e.g., interface definitions)
|
|
115
|
+
|
|
116
|
+
**Priority**: L1 > L2 > L3 in order of verifiability importance
|
|
117
|
+
|
|
118
|
+
## Integration Point Definitions
|
|
119
|
+
|
|
120
|
+
Define integration points according to selected strategy:
|
|
121
|
+
- **Strangler-based**: When switching between old and new systems for each feature
|
|
122
|
+
- **Feature-driven**: When users can actually use the feature
|
|
123
|
+
- **Foundation-driven**: When all architecture layers are ready and E2E tests pass
|
|
124
|
+
- **Hybrid**: When individual goals defined for each phase are achieved
|
|
125
|
+
|
|
126
|
+
## Anti-patterns
|
|
127
|
+
|
|
128
|
+
- **Pattern Fixation**: Selecting only from listed strategies without considering unique combinations
|
|
129
|
+
- **Insufficient Analysis**: Skipping Phase 1 analysis framework before strategy selection
|
|
130
|
+
- **Risk Neglect**: Starting implementation without Phase 3 risk analysis matrix
|
|
131
|
+
- **Constraint Ignorance**: Deciding strategy without checking Phase 4 constraint checklist
|
|
132
|
+
- **Rationale Omission**: Selecting strategy without using Phase 6 documentation template
|
|
133
|
+
|
|
134
|
+
## Guidelines for Meta-cognitive Execution
|
|
135
|
+
|
|
136
|
+
1. **Leverage Known Patterns**: Use as starting point, explore creative combinations
|
|
137
|
+
2. **Active WebSearch Use**: Research implementation examples from similar tech stacks
|
|
138
|
+
3. **Apply 5 Whys**: Pursue root causes to grasp essence
|
|
139
|
+
4. **Multi-perspective Evaluation**: Comprehensively evaluate from each Phase 1-4 perspective
|
|
140
|
+
5. **Creative Thinking**: Consider sequential application of multiple strategies and designs leveraging project-specific constraints
|
|
141
|
+
6. **Clarify Decision Rationale**: Make strategy selection rationale explicit in design documents
|