@minhduydev/mdpi 0.4.1 → 0.5.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 (34) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.pi/VERSION +1 -1
  3. package/dist/template/.pi/extensions/templates-injector.ts +35 -7
  4. package/dist/template/.pi/prompts/INDEX.md +3 -9
  5. package/dist/template/.pi/skills/INDEX.md +39 -8
  6. package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
  7. package/dist/template/.pi/skills/frontend-design/SKILL.md +1 -1
  8. package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +88 -15
  9. package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +148 -13
  10. package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +127 -20
  11. package/dist/template/.pi/skills/nextjs-app-router/SKILL.md +334 -0
  12. package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -0
  13. package/dist/template/.pi/skills/react-best-practices/SKILL.md +79 -1
  14. package/dist/template/.pi/skills/react-compiler/SKILL.md +237 -0
  15. package/dist/template/.pi/skills/react-hook-form/SKILL.md +374 -0
  16. package/dist/template/.pi/skills/react-server-actions/SKILL.md +299 -0
  17. package/dist/template/.pi/skills/shadcn-ui/SKILL.md +404 -0
  18. package/dist/template/.pi/skills/tanstack-query/SKILL.md +330 -0
  19. package/dist/template/.pi/skills/v0/SKILL.md +264 -0
  20. package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
  21. package/package.json +1 -1
  22. package/dist/template/.pi/prompts/loop-check.md +0 -87
  23. package/dist/template/.pi/prompts/loop-init.md +0 -157
  24. package/dist/template/.pi/prompts/loop-review.md +0 -90
  25. package/dist/template/.pi/skills/loop-audit/SKILL.md +0 -141
  26. package/dist/template/.pi/skills/loop-cost/SKILL.md +0 -130
  27. package/dist/template/.pi/skills/loop-engineering/SKILL.md +0 -175
  28. package/dist/template/.pi/templates/loop-github-action.yml +0 -162
  29. package/dist/template/.pi/templates/loop-orchestrator.sh +0 -514
  30. package/dist/template/.pi/templates/loop-orchestrator.test.ts +0 -332
  31. package/dist/template/.pi/templates/loop-orchestrator.ts +0 -936
  32. package/dist/template/.pi/templates/loop-state.json +0 -24
  33. package/dist/template/.pi/templates/loop-state.md +0 -98
  34. package/dist/template/.pi/templates/loop-vision.md +0 -110
@@ -0,0 +1,330 @@
1
+ ---
2
+ name: tanstack-query
3
+ description: Use when implementing data fetching, caching, or mutations with TanStack Query v5. Covers useQuery, useMutation, optimistic updates, infinite queries, prefetching, SSR patterns, query keys. MUST load before any data fetching implementation.
4
+ ---
5
+
6
+ # TanStack Query v5
7
+
8
+ ## When to Use
9
+
10
+ - Fetching data from APIs in React applications
11
+ - Managing server state with automatic caching and background refetching
12
+ - Implementing optimistic updates for mutations
13
+ - Handling pagination and infinite scrolling
14
+ - Prefetching data for faster navigation
15
+ - Server-side rendering with client hydration
16
+
17
+ ## When NOT to Use
18
+
19
+ - Server Components with direct DB access (use `use cache` instead)
20
+ - WebSocket-only real-time data (use SWR subscription or custom hook)
21
+ - Form state management (use React Hook Form)
22
+ - Global client-only state (use Zustand)
23
+
24
+ ## Setup
25
+
26
+ ```tsx
27
+ // app/providers.tsx
28
+ 'use client'
29
+
30
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
31
+ import { useState } from 'react'
32
+
33
+ export function Providers({ children }: { children: React.ReactNode }) {
34
+ const [queryClient] = useState(
35
+ () => new QueryClient({
36
+ defaultOptions: {
37
+ queries: {
38
+ staleTime: 60 * 1000, // 1 min before considered stale
39
+ gcTime: 5 * 60 * 1000, // 5 min garbage collection
40
+ retry: 1, // One retry on failure
41
+ refetchOnWindowFocus: false,
42
+ },
43
+ },
44
+ })
45
+ )
46
+
47
+ return (
48
+ <QueryClientProvider client={queryClient}>
49
+ {children}
50
+ </QueryClientProvider>
51
+ )
52
+ }
53
+ ```
54
+
55
+ ```tsx
56
+ // app/layout.tsx
57
+ import { Providers } from './providers'
58
+
59
+ export default function RootLayout({ children }) {
60
+ return (
61
+ <html>
62
+ <body>
63
+ <Providers>{children}</Providers>
64
+ </body>
65
+ </html>
66
+ )
67
+ }
68
+ ```
69
+
70
+ ## useQuery — Basic Data Fetching
71
+
72
+ ```tsx
73
+ 'use client'
74
+
75
+ import { useQuery } from '@tanstack/react-query'
76
+
77
+ function PostsList() {
78
+ const { data, isLoading, error } = useQuery({
79
+ queryKey: ['posts'],
80
+ queryFn: () => fetch('/api/posts').then(res => res.json()),
81
+ })
82
+
83
+ if (isLoading) return <PostsSkeleton />
84
+ if (error) return <ErrorDisplay error={error} />
85
+
86
+ return data.map(post => <PostCard key={post.id} post={post} />)
87
+ }
88
+ ```
89
+
90
+ ## Query Key Design
91
+
92
+ ```tsx
93
+ // Flat keys — simple
94
+ useQuery({ queryKey: ['posts'], queryFn: fetchPosts })
95
+
96
+ // Hierarchical keys — filterable
97
+ useQuery({ queryKey: ['posts', { status: 'published' }], queryFn: () => fetchPosts('published') })
98
+
99
+ // Detail queries — id-based
100
+ useQuery({ queryKey: ['posts', postId], queryFn: () => fetchPost(postId) })
101
+
102
+ // Factory pattern — recommended for large apps
103
+ const postKeys = {
104
+ all: ['posts'] as const,
105
+ lists: () => [...postKeys.all, 'list'] as const,
106
+ list: (filters: Filters) => [...postKeys.lists(), filters] as const,
107
+ details: () => [...postKeys.all, 'detail'] as const,
108
+ detail: (id: string) => [...postKeys.details(), id] as const,
109
+ }
110
+
111
+ // Usage:
112
+ useQuery({ queryKey: postKeys.lists({ status: 'published' }), ... })
113
+ useQuery({ queryKey: postKeys.detail(id), ... })
114
+
115
+ // Invalidation
116
+ queryClient.invalidateQueries({ queryKey: postKeys.lists() }) // All lists
117
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(id) }) // Specific post
118
+ ```
119
+
120
+ ## useMutation
121
+
122
+ ```tsx
123
+ import { useMutation, useQueryClient } from '@tanstack/react-query'
124
+
125
+ function CreatePost() {
126
+ const queryClient = useQueryClient()
127
+
128
+ const mutation = useMutation({
129
+ mutationFn: (newPost: PostInput) =>
130
+ fetch('/api/posts', {
131
+ method: 'POST',
132
+ body: JSON.stringify(newPost),
133
+ }),
134
+
135
+ // Invalidate and refetch after success
136
+ onSuccess: () => {
137
+ queryClient.invalidateQueries({ queryKey: ['posts'] })
138
+ },
139
+ })
140
+
141
+ return (
142
+ <button
143
+ disabled={mutation.isPending}
144
+ onClick={() => mutation.mutate({ title: 'New Post' })}
145
+ >
146
+ {mutation.isPending ? 'Creating...' : 'Create Post'}
147
+ </button>
148
+ )
149
+ }
150
+ ```
151
+
152
+ ## Optimistic Updates
153
+
154
+ ```tsx
155
+ const mutation = useMutation({
156
+ mutationFn: toggleTodoStatus,
157
+
158
+ onMutate: async (todoId) => {
159
+ // Cancel outgoing refetches
160
+ await queryClient.cancelQueries({ queryKey: ['todos'] })
161
+
162
+ // Snapshot previous value
163
+ const previousTodos = queryClient.getQueryData(['todos'])
164
+
165
+ // Optimistically update
166
+ queryClient.setQueryData(['todos'], (old: Todo[]) =>
167
+ old.map(t => t.id === todoId ? { ...t, done: !t.done } : t)
168
+ )
169
+
170
+ // Return context for rollback
171
+ return { previousTodos }
172
+ },
173
+
174
+ onError: (err, todoId, context) => {
175
+ // Rollback on failure
176
+ queryClient.setQueryData(['todos'], context?.previousTodos)
177
+ },
178
+
179
+ onSettled: () => {
180
+ // Refetch to sync with server
181
+ queryClient.invalidateQueries({ queryKey: ['todos'] })
182
+ },
183
+ })
184
+ ```
185
+
186
+ ## Infinite Queries
187
+
188
+ ```tsx
189
+ import { useInfiniteQuery } from '@tanstack/react-query'
190
+
191
+ function PostFeed() {
192
+ const {
193
+ data,
194
+ fetchNextPage,
195
+ hasNextPage,
196
+ isFetchingNextPage,
197
+ } = useInfiniteQuery({
198
+ queryKey: ['posts', 'infinite'],
199
+ queryFn: ({ pageParam }) =>
200
+ fetch(`/api/posts?cursor=${pageParam}`).then(r => r.json()),
201
+ initialPageParam: 0,
202
+ getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
203
+ })
204
+
205
+ return (
206
+ <div>
207
+ {data.pages.map(page =>
208
+ page.posts.map(post => <PostCard key={post.id} post={post} />)
209
+ )}
210
+ {hasNextPage && (
211
+ <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
212
+ Load more
213
+ </button>
214
+ )}
215
+ </div>
216
+ )
217
+ }
218
+ ```
219
+
220
+ ## Prefetching (Next.js)
221
+
222
+ ```tsx
223
+ // app/posts/page.tsx — Server Component
224
+ import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
225
+ import { PostsList } from './PostsList'
226
+
227
+ export default async function PostsPage() {
228
+ const queryClient = new QueryClient()
229
+
230
+ // Prefetch on server
231
+ await queryClient.prefetchQuery({
232
+ queryKey: ['posts'],
233
+ queryFn: fetchPosts,
234
+ })
235
+
236
+ return (
237
+ <HydrationBoundary state={dehydrate(queryClient)}>
238
+ <PostsList />
239
+ </HydrationBoundary>
240
+ )
241
+ }
242
+ ```
243
+
244
+ ```tsx
245
+ // app/posts/PostsList.tsx — Client Component
246
+ 'use client'
247
+
248
+ import { useQuery } from '@tanstack/react-query'
249
+
250
+ export function PostsList() {
251
+ // Uses prefetched data — no loading state on first render
252
+ const { data } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts })
253
+ return data.map(post => <PostCard key={post.id} post={post} />)
254
+ }
255
+ ```
256
+
257
+ ## Combining with Server Actions
258
+
259
+ ```tsx
260
+ // Use Server Actions for mutations, TanStack Query for reads:
261
+
262
+ 'use client'
263
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
264
+ import { createPost } from './actions' // Server Action
265
+
266
+ function PostsPage() {
267
+ const queryClient = useQueryClient()
268
+
269
+ // Read — TanStack Query
270
+ const posts = useQuery({
271
+ queryKey: ['posts'],
272
+ queryFn: () => fetch('/api/posts').then(r => r.json()),
273
+ })
274
+
275
+ // Write — Server Action + cache revalidation
276
+ const mutation = useMutation({
277
+ mutationFn: (data: FormData) => createPost(null, data),
278
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['posts'] }),
279
+ })
280
+
281
+ return (
282
+ <form action={mutation.mutate}>
283
+ <input name="title" />
284
+ <button>Create</button>
285
+ </form>
286
+ )
287
+ }
288
+ ```
289
+
290
+ ## staleTime vs gcTime
291
+
292
+ | Setting | What it controls | Recommended |
293
+ |---------|-----------------|-------------|
294
+ | `staleTime` | How long before data is considered stale and refetched | 30s–5min depending on update frequency |
295
+ | `gcTime` | How long inactive data stays in cache before garbage collection | 5–30min (longer than staleTime) |
296
+
297
+ ```tsx
298
+ // Static data — rarely changes
299
+ staleTime: Infinity, gcTime: 30 * 60 * 1000,
300
+
301
+ // Dashboard — updates every few minutes
302
+ staleTime: 5 * 60 * 1000, gcTime: 30 * 60 * 1000,
303
+
304
+ // Real-time feed — updates frequently
305
+ staleTime: 30 * 1000, gcTime: 5 * 60 * 1000,
306
+ ```
307
+
308
+ ## Common Pitfalls
309
+
310
+ | Pitfall | Fix |
311
+ |---------|-----|
312
+ | Using TanStack Query in Server Components | Move to `'use client'` component |
313
+ | `queryKey` as `['posts']` everywhere — no granularity | Use structured keys: `['posts', 'list', filters]` |
314
+ | Not setting `staleTime` — defaults to 0 | Set sensible `staleTime` — default 0 refetches too often |
315
+ | Mixing `isLoading` and `isFetching` | `isLoading` = first load; `isFetching` = any fetch including background |
316
+ | `useQuery` for mutations | `useQuery` is for reads; use `useMutation` for writes |
317
+ | Mutating cache directly without rollback | Always implement `onMutate` snapshot + `onError` rollback |
318
+ | Missing `HydrationBoundary` for SSR | Server-prefetched data won't hydrate without it |
319
+ | `queryClient` recreated every render | Wrap in `useState(() => new QueryClient(...))` |
320
+
321
+ ## Verification
322
+
323
+ - [ ] `QueryClientProvider` wraps the app in root layout
324
+ - [ ] `staleTime` and `gcTime` configured globally (not per-query unless needed)
325
+ - [ ] Query keys follow a structured pattern (all → lists → detail)
326
+ - [ ] Mutations call `invalidateQueries` or use optimistic updates
327
+ - [ ] Optimistic updates have rollback via `onError` + `onMutate` snapshot
328
+ - [ ] SSR pages use `HydrationBoundary` with `dehydrate`
329
+ - [ ] No `useQuery` in Server Components
330
+ - [ ] `isLoading` used for first-load skeleton; `isFetching` for background updates
@@ -0,0 +1,264 @@
1
+ ---
2
+ name: v0
3
+ description: Use when generating UI with v0 (Vercel's AI-powered generator). Covers prompt engineering, CLI/SDK/MCP integration, shadcn/ui-aware patterns. MUST load before any v0 workflow.
4
+ ---
5
+
6
+ # v0 — Vercel AI UI Generator
7
+
8
+ ## Overview
9
+
10
+ v0 (v0.app) is Vercel's AI-powered UI and application generator. It generates React components using **shadcn/ui** primitives + **Tailwind CSS**, targeting **Next.js App Router** by default.
11
+
12
+ In February 2026, v0 evolved to **v2.0** — a full production development platform. Beyond UI generation, it now supports: importing GitHub repos into sandboxes, git branching/PRs/merging from the browser, database integrations (Snowflake, AWS DBs), enterprise SSO, and agent-based workflows.
13
+
14
+ v0 generates "code that looks like a senior frontend engineer wrote it."
15
+
16
+ ## When to Use
17
+
18
+ - Generating shadcn/ui components or pages with AI
19
+ - Writing effective v0 prompts using the 5-block brief
20
+ - Adding v0-generated code to projects via CLI or SDK
21
+ - Integrating v0 with IDEs via MCP (`https://mcp.v0.dev`)
22
+ - Building programmatic UI generation workflows with the v0 SDK
23
+ - Designing brand-aware v0 output via custom shadcn/ui registries
24
+
25
+ ## When NOT to Use
26
+
27
+ - Plain UI without AI generation (use `frontend-design` skill)
28
+ - Backend-only or non-UI tasks
29
+ - When you already have the component and only need manual edits
30
+
31
+ ## Relationship to Other Skills
32
+
33
+ | Skill | Role |
34
+ |-------|------|
35
+ | `shadcn-ui` | Upstream — ensures shadcn/ui is configured correctly before v0 generation |
36
+ | `frontend-design` | Downstream — use for manual refinement of v0 output, design system application |
37
+ | `design-taste-frontend` | Aesthetic baseline applied to v0 generations |
38
+
39
+ **Pipeline**: `shadcn-ui` → `v0` → `frontend-design`
40
+
41
+ ## Prompt Engineering: The 5-Block Component Brief
42
+
43
+ Every v0 prompt should include these 5 blocks. Missing blocks = v0 guesses = expensive iterations.
44
+
45
+ | # | Block | Question | Example |
46
+ |---|-------|----------|---------|
47
+ | 1 | **What it is** | What component? | "A subscription pricing card for a SaaS dashboard" |
48
+ | 2 | **Behavior** | How does it work? | "Three tiers (Free/Pro/Enterprise), monthly/yearly toggle switches pricing, clicking a tier highlights it" |
49
+ | 3 | **States** | What states? | "Loading spinner while pricing loads, error state if fetch fails, empty state if no tiers returned" |
50
+ | 4 | **Props / Data Shape** | What's the contract? | "`tiers: Tier[]`, `billing: 'monthly' | 'yearly'`, `onSelect: (tier) => void`" |
51
+ | 5 | **Visual Intent** | What should it look like? | "shadcn Card layout, data-first, accent color on recommended tier, generous whitespace, no shadows" |
52
+
53
+ ### Prompt Patterns
54
+
55
+ | Pattern | Example | Why |
56
+ |---------|---------|-----|
57
+ | **Constraint anchoring** | "Use only shadcn/ui primitives and Tailwind classes" | Prevents unknown imports |
58
+ | **Negative instruction** | "Do not use inline styles or external CSS files" | Eliminates anti-patterns |
59
+ | **Type contract** | "Define TypeScript interface for all props first" | Forces explicit API surface |
60
+ | **Responsive breakpoints** | "Mobile-first: stack on sm, 2-col on md, 3-col on lg" | Correct Tailwind prefixes |
61
+ | **State specification** | "Lift filter state to the parent via onFilterChange" | Proper unidirectional data flow |
62
+ | **System context** | "You are generating for Next.js App Router with shadcn/ui Vega style..." | Foundation for consistency |
63
+
64
+ ### Anti-Patterns in Prompts
65
+
66
+ | Anti-Pattern | Fix |
67
+ |-------------|-----|
68
+ | One-word prompt ("Pricing page") | Write a 5-block brief |
69
+ | Generating full pages | Generate component by component, compose pages manually |
70
+ | Hard-coded data | Generate data-less components, wire real data separately |
71
+ | "Make it look like Stripe" | Describe visual intent concretely, not by brand reference |
72
+ | 10+ refinements in one follow-up | 1-2 changes per loop; rewrite brief from scratch if complex |
73
+ | UI-first architecture | Design API/schema first, then generate UI that matches it |
74
+ | Passing API secrets through prompts | Never send secrets through v0 chat |
75
+
76
+ ## Integration Paths
77
+
78
+ ### Path A — shadcn CLI Pull (Recommended)
79
+
80
+ 1. Generate UI on [v0.app](https://v0.app)
81
+ 2. Click **"Add to Codebase"** → copy the command:
82
+ ```bash
83
+ npx shadcn@latest add "https://v0.dev/chat/b/<project_id>?token=<token>"
84
+ ```
85
+ 3. Run in your project root — pulls component + installs deps
86
+
87
+ ### Path B — v0 CLI
88
+
89
+ ```bash
90
+ # One-time setup in existing Next.js project
91
+ npx v0@latest init
92
+
93
+ # Add specific generated component by ID
94
+ npx v0@latest add <id>
95
+ ```
96
+
97
+ The `v0` CLI (v2.2.5) installs deps: `@radix-ui/react-icons`, `clsx`, `lucide-react`.
98
+
99
+ ### Path C — SDK (Programmatic)
100
+
101
+ ```bash
102
+ npm install v0-sdk
103
+ ```
104
+
105
+ ```typescript
106
+ import { v0 } from 'v0-sdk'
107
+
108
+ const client = v0.createClient({ apiKey: process.env.V0_API_KEY })
109
+
110
+ // Create a chat
111
+ const chat = await client.chats.create({
112
+ message: "Build a pricing card with three tiers and monthly/yearly toggle"
113
+ })
114
+
115
+ // Stream the response
116
+ for await (const chunk of chat.stream()) {
117
+ console.log(chunk)
118
+ }
119
+
120
+ // Initialize with existing files
121
+ await client.chats.init({
122
+ files: [{ path: 'components/ui/button.tsx', content: '...' }]
123
+ })
124
+ ```
125
+
126
+ ### v0 SDK Ecosystem
127
+
128
+ | Package | Version | Purpose |
129
+ |---------|---------|---------|
130
+ | `v0-sdk` | 0.16.4 | Core TypeScript SDK — chats, projects, deployments |
131
+ | `@v0-sdk/react` | 0.5.0 | Headless React components for v0 content |
132
+ | `@v0-sdk/ai-tools` | 0.3.8 | AI SDK tools for agents (~20 tools) |
133
+ | `create-v0-sdk-app` | 0.2.1 | Scaffold SDK-powered apps |
134
+
135
+ ### Path D — MCP Server
136
+
137
+ Connect IDEs to v0 via MCP:
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "v0": {
143
+ "command": "npx",
144
+ "args": ["mcp-remote", "https://mcp.v0.dev", "--header", "Authorization: Bearer ${V0_API_KEY}"]
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Supports: Cursor, Claude Desktop, VS Code, Windsurf, any MCP-compatible IDE.
151
+
152
+ ## Platform API (Public Beta)
153
+
154
+ REST API at `https://api.v0.dev/v1`. Covers: chats, projects, deployments, users, webhooks, MCP servers.
155
+
156
+ ```typescript
157
+ // Direct REST
158
+ const res = await fetch('https://api.v0.dev/v1/chats', {
159
+ method: 'POST',
160
+ headers: {
161
+ 'Authorization': `Bearer ${process.env.V0_API_KEY}`,
162
+ 'Content-Type': 'application/json'
163
+ },
164
+ body: JSON.stringify({
165
+ message: "Build a login form with email/password fields"
166
+ })
167
+ })
168
+ ```
169
+
170
+ ## Integration with shadcn/ui
171
+
172
+ v0 generates code using shadcn/ui by default. Key integration points:
173
+
174
+ - **Before generating**: Run `npx shadcn init` in your project
175
+ - **Custom design systems**: Publish a shadcn/ui Registry with your design tokens → v0 generates brand-consistent output
176
+ - **Registry MCP**: Connect your registry to v0 for design-aware generation
177
+ - **`components.json`**: v0 respects your project's aliases and style config
178
+ - **Check deps**: After pulling v0 code, verify all shadcn components are installed
179
+
180
+ ### Design System Integration
181
+
182
+ ```json
183
+ // components.json — exposed to v0 for brand-aware generation
184
+ {
185
+ "style": "vega",
186
+ "tsx": true,
187
+ "tailwind": { "cssVariables": true },
188
+ "aliases": { "components": "@/components", "ui": "@/components/ui" }
189
+ }
190
+ ```
191
+
192
+ ## v0 2.0 Platform (Feb 2026)
193
+
194
+ Key capabilities beyond UI generation:
195
+
196
+ - **Import any GitHub repo** into sandbox with auto-pulled Vercel env vars
197
+ - **Git panel** — branching, PRs, merging from the browser
198
+ - **DB integrations** — Snowflake, AWS databases, Neon + Drizzle scaffolding
199
+ - **Enterprise** — deployment protection, access controls, SSO, signed Git commits
200
+ - **Agents** — plan and build end-to-end agentic workflows
201
+ - **Design Mode** — floating toolbar, layers viewer, measure overlay
202
+ - **Cmd+K** — command palette navigation
203
+ - **Shopify integration** — storefront building
204
+ - **Auto merge conflict resolution**
205
+
206
+ ## Best Patterns
207
+
208
+ ### Component-First Decomposition
209
+
210
+ Instead of: "Build a dashboard page"
211
+
212
+ Do:
213
+ 1. Generate `StatCard` → pull → verify
214
+ 2. Generate `DataTable` → pull → verify
215
+ 3. Generate `ChartWidget` → pull → verify
216
+ 4. Compose in the page manually
217
+
218
+ ### System Prompt Template
219
+
220
+ When using the SDK or Platform API, set a system prompt:
221
+
222
+ ```
223
+ You are a shadcn/ui component generator.
224
+ Framework: Next.js 15+ App Router.
225
+ Language: TypeScript strict mode.
226
+ Styling: Tailwind CSS v4 with CSS variables.
227
+ Imports: use @/ path alias.
228
+ Data: accept via props, never hard-code.
229
+ States: loading, empty, error, normal.
230
+ Accessibility: ARIA labels, keyboard nav, focus management.
231
+ Dark mode: CSS variable overrides.
232
+ ```
233
+
234
+ ### v0 → Production Workflow
235
+
236
+ 1. **Spec** → Define data model, user flow, design tokens
237
+ 2. **Generate** → v0 with 5-block brief for each component
238
+ 3. **Pull** → Add to codebase via CLI
239
+ 4. **Review** → Check TypeScript types, accessibility, theme compliance
240
+ 5. **Wire** → Connect real data sources, auth, API routes
241
+ 6. **Harden** → Loading states, error boundaries, edge cases
242
+ 7. **Deploy** → Vercel preview + production
243
+
244
+ ## Common Pitfalls
245
+
246
+ | Pitfall | Fix |
247
+ |---------|-----|
248
+ | Treating v0 output as production-ready | v0 handles presentation only — you need auth, data, logic |
249
+ | Letting v0 define your data model | Your domain expertise defines the model; v0 adapts |
250
+ | Client-only generation | Plan SSR boundaries; v0 generates client components by default |
251
+ | Not checking shadcn deps before pulling | `npx shadcn info --json` to verify installed components |
252
+ | Generating without design tokens | Set system prompt with CSS variable references |
253
+ | Skipping review | Every v0 component needs human review for correctness |
254
+
255
+ ## Verification
256
+
257
+ - [ ] Generated components use project design tokens (CSS variables, not hard-coded hex)
258
+ - [ ] All components accept typed props (no hard-coded data)
259
+ - [ ] Loading, empty, error states handled
260
+ - [ ] Required shadcn/ui primitives installed (`npx shadcn info --json`)
261
+ - [ ] TypeScript compiles without errors
262
+ - [ ] Keyboard navigation and ARIA labels verified
263
+ - [ ] Light and dark mode both render correctly
264
+ - [ ] Components refactored for reusability (not page-specific)