@minhduydev/mdpi 0.4.0 → 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 (48) 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 +34 -6
  4. package/dist/template/.pi/prompts/INDEX.md +3 -9
  5. package/dist/template/.pi/skills/INDEX.md +81 -19
  6. package/dist/template/.pi/skills/accessibility-audit/SKILL.md +8 -2
  7. package/dist/template/.pi/skills/baseline-ui/SKILL.md +211 -0
  8. package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
  9. package/dist/template/.pi/skills/design-taste-frontend/SKILL.md +53 -42
  10. package/dist/template/.pi/skills/fixing-accessibility/SKILL.md +509 -0
  11. package/dist/template/.pi/skills/frontend-design/SKILL.md +60 -47
  12. package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +88 -15
  13. package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +148 -13
  14. package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +127 -20
  15. package/dist/template/.pi/skills/frontend-ui-engineering/SKILL.md +21 -27
  16. package/dist/template/.pi/skills/nextjs-app-router/SKILL.md +334 -0
  17. package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -0
  18. package/dist/template/.pi/skills/oklch-color-workflow/SKILL.md +426 -0
  19. package/dist/template/.pi/skills/production-hardening/SKILL.md +652 -0
  20. package/dist/template/.pi/skills/react-best-practices/SKILL.md +79 -1
  21. package/dist/template/.pi/skills/react-compiler/SKILL.md +237 -0
  22. package/dist/template/.pi/skills/react-hook-form/SKILL.md +374 -0
  23. package/dist/template/.pi/skills/react-server-actions/SKILL.md +299 -0
  24. package/dist/template/.pi/skills/shadcn-ui/SKILL.md +404 -0
  25. package/dist/template/.pi/skills/tanstack-query/SKILL.md +330 -0
  26. package/dist/template/.pi/skills/ui-craft-principles/SKILL.md +564 -0
  27. package/dist/template/.pi/skills/ui-quality-audit/SKILL.md +329 -0
  28. package/dist/template/.pi/skills/v0/SKILL.md +264 -0
  29. package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
  30. package/dist/template/.pi/templates/DESIGN.md +76 -0
  31. package/dist/template/.pi/workflows/INDEX.md +2 -1
  32. package/dist/template/.pi/workflows/frontend-feature-workflow.md +343 -0
  33. package/dist/template/.pi/workflows/quality-loop.md +1 -1
  34. package/package.json +1 -1
  35. package/dist/template/.pi/prompts/loop-check.md +0 -87
  36. package/dist/template/.pi/prompts/loop-init.md +0 -157
  37. package/dist/template/.pi/prompts/loop-review.md +0 -90
  38. package/dist/template/.pi/skills/loop-audit/SKILL.md +0 -141
  39. package/dist/template/.pi/skills/loop-cost/SKILL.md +0 -130
  40. package/dist/template/.pi/skills/loop-engineering/SKILL.md +0 -175
  41. package/dist/template/.pi/templates/loop-github-action.yml +0 -162
  42. package/dist/template/.pi/templates/loop-orchestrator.sh +0 -514
  43. package/dist/template/.pi/templates/loop-orchestrator.test.ts +0 -332
  44. package/dist/template/.pi/templates/loop-orchestrator.ts +0 -936
  45. package/dist/template/.pi/templates/loop-state.json +0 -24
  46. package/dist/template/.pi/templates/loop-state.md +0 -98
  47. package/dist/template/.pi/templates/loop-vision.md +0 -110
  48. /package/dist/template/.pi/templates/{design.md → feature-design.md} +0 -0
@@ -1,56 +1,161 @@
1
1
  # shadcn/ui Setup
2
2
 
3
- CLI v3.6.x (current: v3.6.3) - Copy-paste components, Radix UI + Tailwind v4.
3
+ CLI v4.x (current: shadcn@4.11.0) Copy-paste components, Radix UI / Base UI + Tailwind v4.
4
4
 
5
- ## New Project
5
+ ## Create a New Project
6
6
 
7
7
  ```bash
8
8
  npx shadcn create
9
9
  ```
10
10
 
11
11
  Interactive setup:
12
- - Visual style: Vega, Nova, Maia, Lyra, Mira
13
- - Component library: Radix UI or Base UI
14
- - Icon library (including Phosphor)
15
- - Next.js 16 support
12
+ - **Visual style**: Vega, Nova, Maia, Lyra, Mira
13
+ - **Component library**: Radix UI or Base UI
14
+ - **Icon library** (Lucide, Phosphor, etc.)
15
+ - **Next.js 16**, Vite, Laravel, React Router, Astro, TanStack Start support
16
+ - **Template scaffolding** via `npx shadcn init --template`
16
17
 
17
18
  ## Existing Project
18
19
 
19
20
  ```bash
20
- npx shadcn@latest init
21
+ npx shadcn@latest init --preset <code>
21
22
  npx shadcn@latest add button card dialog
22
23
  npx shadcn@latest add --all
24
+ npx shadcn@latest add <username>/<repo>/<item> # GitHub Registry
23
25
  ```
24
26
 
25
27
  Components install to `components/ui/`.
26
28
 
29
+ ## Key CLI v4 Commands
30
+
31
+ ```bash
32
+ # Inspection
33
+ npx shadcn info # Full project config (for agent context)
34
+ npx shadcn info --json # JSON output for programmatic use
35
+ npx shadcn docs <component> # Docs, code, examples from CLI
36
+
37
+ # Preview changes before writing
38
+ npx shadcn add button --dry-run # Show what will be installed
39
+ npx shadcn add button --diff # Show diff against current
40
+ npx shadcn add button --view # Open component in browser
41
+
42
+ # Project setup flags
43
+ npx shadcn init --preset a1Dg5eFl # Pack entire design system into short code
44
+ npx shadcn init --template # Scaffold project templates
45
+ npx shadcn init --monorepo # Monorepo setup
46
+ npx shadcn init --base radix # Choose primitives (radix | base)
47
+
48
+ # Skills (AI Agent)
49
+ npx skills add shadcn/ui # Install agent prompt file
50
+ npx shadcn skills generate # Regenerate after adding components
51
+ npx shadcn skills update # Update monthly
52
+ ```
53
+
27
54
  ## Visual Styles
28
55
 
29
- | Style | Description |
30
- |-------|-------------|
31
- | **Vega** | Classic shadcn look |
32
- | **Nova** | Reduced padding, compact |
33
- | **Maia** | Soft, rounded, generous |
34
- | **Lyra** | Boxy, sharp, mono fonts |
35
- | **Mira** | Compact, dense interfaces |
56
+ | Style | Characteristics |
57
+ |-------|----------------|
58
+ | **Vega** | Classic shadcn look — balanced, versatile |
59
+ | **Nova** | Reduced padding, compact, space-efficient |
60
+ | **Maia** | Soft, rounded corners, generous spacing |
61
+ | **Lyra** | Boxy, sharp corners, monospace fonts |
62
+ | **Mira** | Compact, dense, data-heavy interfaces |
63
+
64
+ Styles rewrite component code, not just CSS — fonts, spacing, structure, primitives all adapt.
65
+
66
+ ## Presets
67
+
68
+ Presets pack the entire design system into a reproducible short code:
69
+
70
+ ```bash
71
+ # Export your preset
72
+ npx shadcn preset export
73
+
74
+ # Init a project with a preset
75
+ npx shadcn init --preset a1Dg5eFl
76
+ ```
77
+
78
+ A preset includes: colors, theme, icons, fonts, radius, spacing — everything in one code.
36
79
 
37
80
  ## Component Libraries
38
81
 
39
- - **Radix UI** (default): Full accessibility, React-only
40
- - **Base UI**: MUI unstyled components
82
+ - **Radix UI** (default): Full accessibility, React-only, battle-tested
83
+ - **Base UI**: MUI unstyled components, headless
84
+
85
+ Select during `npx shadcn create` or with `--base` flag. CLI auto-detects your library when pulling components.
86
+
87
+ ## GitHub Registries (June 2026)
88
+
89
+ Any public GitHub repo with a `registry.json` can be a component registry:
41
90
 
42
- Select during `npx shadcn create` or in `components.json`.
91
+ ```bash
92
+ npx shadcn@latest add <username>/<repo>/<item>
93
+ ```
94
+
95
+ Distribute: components, hooks, utilities, design tokens, feature kits, project conventions, CI workflows, templates. No build step — CLI reads `registry.json` directly.
96
+
97
+ ```json
98
+ // registry.json (in any GitHub repo)
99
+ {
100
+ "name": "my-components",
101
+ "items": [
102
+ {
103
+ "name": "data-table",
104
+ "type": "registry:component",
105
+ "files": [{ "path": "components/data-table.tsx" }]
106
+ }
107
+ ]
108
+ }
109
+ ```
110
+
111
+ ## shadcn/skills — AI Agent Bridge
112
+
113
+ ```bash
114
+ npx skills add shadcn/ui
115
+ ```
116
+
117
+ Creates `.shadcn/skills.md` — a machine-readable file that gives AI coding agents project-aware context:
118
+
119
+ - **Project context** — framework, aliases, installed components, icon library, base library (via `shadcn info --json`)
120
+ - **CLI command reference** — all flags, smart merge, presets, templates
121
+ - **Theming guidance** — CSS vars, OKLCH, dark mode, Tailwind v3/v4
122
+ - **Registry authoring** — `registry.json` format
123
+ - **Pattern enforcement** — FieldGroup for forms, ToggleGroup for options, semantic colors
124
+
125
+ **Measured impact**: API errors 34% → 3%, correct variants 61% → 98%, first-try success 45% → 89%.
126
+
127
+ **Critical workflows**:
128
+ - Re-generate after adding components: `npx shadcn skills generate`
129
+ - Update monthly: `npx shadcn skills update`
130
+ - Reference file path (don't paste into context — 4K cutoff)
43
131
 
44
132
  ## MCP Server Support
45
133
 
46
- - OpenCode MCP (v3.6.3)
47
- - Codex MCP (v3.4.0)
134
+ Connect AI editors to your registry:
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "shadcn": {
140
+ "command": "npx",
141
+ "args": ["-y", "shadcn@canary", "registry:mcp"],
142
+ "env": {
143
+ "REGISTRY_URL": "https://your-registry.vercel.app/r/registry.json"
144
+ }
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Also: OpenCode MCP (v3.6.3), Codex MCP (v3.4.0).
48
151
 
49
152
  ## Registry System
50
153
 
51
154
  - Registry Directory: https://ui.shadcn.com/docs/directory
52
155
  - Custom registries via `components.json`
53
156
  - Namespaced components
157
+ - `registry:base` — distribute entire design systems
158
+ - `registry:font` — distribute font packages
54
159
 
55
160
  ## Component List
56
161
 
@@ -66,4 +171,6 @@ Select during `npx shadcn create` or in `components.json`.
66
171
 
67
172
  **Overlay**: Dropdown Menu, Context Menu, Popover, Collapsible
68
173
 
69
- **Other**: Toggle, Toggle Group, Kbd, Button Group, Item, Empty, Input OTP
174
+ **2026 New**: Spinner, Kbd, KbdGroup, Button Group, Input Group, Field, Item, Empty, Input OTP
175
+
176
+ **Other**: Toggle, Toggle Group
@@ -30,14 +30,15 @@ This skill composes with others for a complete frontend quality pipeline:
30
30
 
31
31
  | Skill | Relationship | When to combine |
32
32
  |-------|-------------|-----------------|
33
- | `frontend-design` | Sibling | `frontend-design` covers general UI patterns with React. `frontend-ui-engineering` adds production-quality standards (accessibility, AI-aesthetic avoidance). Load both for serious UI work. |
34
- | `design-taste-frontend` | Upstream | Apply design-taste rules FIRST to establish the aesthetic baseline. Then use `frontend-ui-engineering` for implementation quality. |
33
+ | `design-taste-frontend` | Upstream | Apply aesthetic baseline FIRST. Then use `frontend-ui-engineering` for implementation quality. |
34
+ | `frontend-design` | Upstream | `frontend-design` covers design system + tokens. `frontend-ui-engineering` adds component implementation patterns. |
35
35
  | `react-best-practices` | Complement | Load when building React/Next.js components — covers performance-specific patterns (memo, useMemo, server components). |
36
- | `accessibility-audit` | Gate | After building UI, run `accessibility-audit` to verify WCAG 2.1 AA compliance. |
36
+ | `baseline-ui` | Upstream | Quick deslop pass before implementation fixes spacing, typography, layout basics automatically. |
37
+ | `fixing-accessibility` | Gate | After building UI, run `fixing-accessibility` for actionable WCAG 2.1 AA fixes. |
37
38
  | `performance-optimization` | Gate | After UI is working, profile with `performance-optimization` for Core Web Vitals. |
38
- | `mockup-to-code` | Upstream | If converting from Figma/mockup, run `mockup-to-code` first, then refine with `frontend-ui-engineering`. |
39
+ | `ui-craft-principles` | Complement | Apply 16 craft principles (concentric radius, optical alignment, etc.) for polish. |
39
40
 
40
- **Pipeline:** `design-taste-frontend` → `frontend-ui-engineering` → `accessibility-audit` + `performance-optimization`
41
+ **Pipeline:** `design-taste-frontend` → `frontend-design` → `frontend-ui-engineering` → `fixing-accessibility` + `performance-optimization`
41
42
 
42
43
  ## Component Architecture
43
44
 
@@ -102,11 +103,11 @@ Global store (Zustand, Redux) → Complex client state shared app-wide
102
103
 
103
104
  ## Design System Adherence
104
105
 
105
- ### Avoid the AI Aesthetic
106
+ ### Avoid Common Visual Anti-Patterns
106
107
 
107
- AI-generated UI has recognizable patterns. Avoid all of them:
108
+ These patterns degrade implementation quality. For design-level aesthetic rules, see `design-taste-frontend`.
108
109
 
109
- | AI Default | Production Quality |
110
+ | Degraded Pattern | Production Quality |
110
111
  |---|---|
111
112
  | Purple/indigo everything | Use the project's actual color palette |
112
113
  | Excessive gradients | Flat or subtle gradients matching the design system |
@@ -185,29 +186,20 @@ Test at: 320px, 768px, 1024px, 1440px.
185
186
  - `aria-busy="true"` on loading regions
186
187
  - Avoid layout shifts during loading (reserve space)
187
188
 
188
- ## Common Rationalizations
189
+ ## Don't
189
190
 
190
- | Rationalization | Reality |
191
- |---|---|
192
- | "Accessibility is a nice-to-have" | It's a legal requirement in many jurisdictions and an engineering quality standard. |
193
- | "We'll make it responsive later" | Retrofitting responsive design is 3x harder than building it from the start. |
194
- | "The design isn't final, so I'll skip styling" | Use the design system defaults. Unstyled UI creates a broken first impression. |
195
- | "This is just a prototype" | Prototypes become production code. Build the foundation right. |
196
- | "The AI aesthetic is fine for now" | It signals low quality. Use the project's actual design system from the start. |
197
-
198
- ## Red Flags
199
-
200
- - Components with more than 200 lines (split them)
201
- - Inline styles or arbitrary pixel values
202
- - Missing error states, loading states, or empty states
203
- - No keyboard navigation testing
204
- - Color as the sole indicator of state (red/green without text or icons)
205
- - Generic "AI look" (purple gradients, oversized cards, stock layouts)
191
+ | Pattern | Replacement | Because |
192
+ |---------|-------------|---------|
193
+ | Components over 200 lines | Split into smaller focused sub-components | Large components violate single responsibility |
194
+ | Inline styles or arbitrary pixel values | Use design tokens and consistent spacing scale | Inline styles are not maintainable |
195
+ | Missing error, loading, or empty states | Handle all 4 data states (loading, empty, error, normal) | Users see blank screens without complete state handling |
196
+ | Color as sole indicator of state | Add text labels or icons alongside color | Color-only cues are inaccessible to colorblind users |
197
+ | `<div onClick>` instead of `<button>` | Use `<button type="button">` with proper styling | div onClick has no keyboard or screen reader semantics |
198
+ | Prop drilling deeper than 3 levels | Use context, composition, or state management | Deep prop drilling couples components unnecessarily |
199
+ | Skipping heading levels (h1 → h3) | Maintain sequential hierarchy (h1 → h2 → h3) | Skipped levels break screen reader page navigation |
206
200
 
207
201
  ## Verification
208
202
 
209
- After building UI:
210
-
211
203
  - [ ] Component renders without console errors
212
204
  - [ ] All interactive elements are keyboard accessible (Tab through the page)
213
205
  - [ ] Screen reader can convey the page's content and structure
@@ -215,3 +207,5 @@ After building UI:
215
207
  - [ ] Loading, error, and empty states all handled
216
208
  - [ ] Follows the project's design system (spacing, colors, typography)
217
209
  - [ ] No accessibility warnings in dev tools or axe-core
210
+ - [ ] No `<div onClick>` as button replacement — all interactive elements use semantic HTML
211
+ - [ ] Components < 200 lines; larger components split into sub-components
@@ -0,0 +1,334 @@
1
+ ---
2
+ name: nextjs-app-router
3
+ description: Use when building or refactoring Next.js App Router pages. Covers file conventions, layouts vs templates, parallel/intercepting routes, route groups, async params, streaming, RSC boundaries. MUST load before any App Router architecture work.
4
+ ---
5
+
6
+ # Next.js App Router Patterns (Next.js 15+)
7
+
8
+ ## When to Use
9
+
10
+ - Building new pages in Next.js App Router
11
+ - Understanding or refactoring App Router file conventions
12
+ - Designing route architecture (parallel routes, intercepting, groups)
13
+ - Setting up layouts, error boundaries, and loading states
14
+ - Making decisions about Server vs Client Components
15
+
16
+ ## When NOT to Use
17
+
18
+ - Pages Router projects (`pages/` directory — use `react-best-practices`)
19
+ - Non-Next.js React projects (Vite, Remix, React Router)
20
+ - Pure API routes (not page structure)
21
+
22
+ ## File Conventions Reference
23
+
24
+ | File | Purpose | Runs |
25
+ |------|---------|------|
26
+ | `page.tsx` | Route's unique UI | Server (default) |
27
+ | `layout.tsx` | Shared UI that persists across navigations | Server (default) |
28
+ | `template.tsx` | Shared UI that remounts on navigation | Server (default) |
29
+ | `loading.tsx` | Suspense fallback while page loads | Server (default) |
30
+ | `error.tsx` | Error boundary for the segment | Client |
31
+ | `not-found.tsx` | 404 UI for the segment | Server (default) |
32
+ | `default.tsx` | Fallback for parallel routes | Server (default) |
33
+ | `route.tsx` | API endpoint for the segment | Server |
34
+
35
+ ## Layout vs Template
36
+
37
+ **Layout**: persists across navigations, state preserved.
38
+
39
+ ```tsx
40
+ // app/dashboard/layout.tsx
41
+ export default function DashboardLayout({ children }: { children: React.ReactNode }) {
42
+ return (
43
+ <div>
44
+ <nav>Sidebar — stays mounted</nav>
45
+ <main>{children}</main>
46
+ </div>
47
+ )
48
+ }
49
+ ```
50
+
51
+ **Template**: remounts on every navigation. Use when you need:
52
+ - Page transitions (AnimatePresence needs remount)
53
+ - `useEffect` that must re-run on navigation
54
+ - Resetting client state between pages
55
+
56
+ ```tsx
57
+ // app/dashboard/template.tsx
58
+ 'use client'
59
+
60
+ import { AnimatePresence, motion } from 'motion/react'
61
+
62
+ export default function Template({ children }: { children: React.ReactNode }) {
63
+ return (
64
+ <AnimatePresence mode="wait">
65
+ <motion.div
66
+ key={usePathname()}
67
+ initial={{ opacity: 0 }}
68
+ animate={{ opacity: 1 }}
69
+ exit={{ opacity: 0 }}
70
+ >
71
+ {children}
72
+ </motion.div>
73
+ </AnimatePresence>
74
+ )
75
+ }
76
+ ```
77
+
78
+ **Rule**: Layout wraps Template wraps Page: `layout.tsx > template.tsx > page.tsx`
79
+
80
+ ## Route Groups — `(group)/`
81
+
82
+ Use parentheses to group routes without affecting the URL:
83
+
84
+ ```
85
+ app/
86
+ ├── (marketing)/
87
+ │ ├── page.tsx → /
88
+ │ ├── about/page.tsx → /about
89
+ │ └── layout.tsx # Marketing layout
90
+ ├── (dashboard)/
91
+ │ ├── dashboard/page.tsx → /dashboard
92
+ │ └── layout.tsx # Dashboard layout (different from marketing)
93
+ ```
94
+
95
+ ## Parallel Routes — `@folder/`
96
+
97
+ Render multiple pages in the same layout simultaneously:
98
+
99
+ ```
100
+ app/
101
+ ├── dashboard/
102
+ │ ├── layout.tsx # Accepts both props:
103
+ │ ├── @analytics/ # children, analytics, team
104
+ │ │ └── page.tsx
105
+ │ ├── @team/
106
+ │ │ └── page.tsx
107
+ │ └── page.tsx # Default children
108
+ ```
109
+
110
+ ```tsx
111
+ // app/dashboard/layout.tsx
112
+ export default function DashboardLayout(props: {
113
+ children: React.ReactNode
114
+ analytics: React.ReactNode
115
+ team: React.ReactNode
116
+ }) {
117
+ return (
118
+ <div className="grid grid-cols-2">
119
+ <div>{props.children}</div>
120
+ <div>{props.analytics}</div>
121
+ <div>{props.team}</div>
122
+ </div>
123
+ )
124
+ }
125
+ ```
126
+
127
+ Each slot needs a `default.tsx` for initial load and unmatched routes.
128
+
129
+ ## Intercepting Routes — `(.)folder/`
130
+
131
+ Render a route in the context of another without full navigation:
132
+
133
+ | Convention | Meaning |
134
+ |-----------|---------|
135
+ | `(.)folder/` | Same level |
136
+ | `(..)folder/` | One level up |
137
+ | `(..)(..)folder/` | Two levels up |
138
+ | `(...)folder/` | From root |
139
+
140
+ Common pattern: Photo modal:
141
+
142
+ ```
143
+ app/
144
+ ├── photos/
145
+ │ ├── page.tsx # Photos grid: /
146
+ │ └── [id]/
147
+ │ └── page.tsx # Photo detail: /photos/1
148
+ └── @modal/
149
+ ├── default.tsx # null return
150
+ └── (.)photos/
151
+ └── [id]/
152
+ └── page.tsx # Modal overlay when navigating from photos grid
153
+ ```
154
+
155
+ ```tsx
156
+ // app/layout.tsx
157
+ export default function RootLayout({ children, modal }) {
158
+ return (
159
+ <>
160
+ {children}
161
+ {modal}
162
+ </>
163
+ )
164
+ }
165
+ ```
166
+
167
+ ## Async Server Components
168
+
169
+ ```tsx
170
+ // app/posts/[id]/page.tsx — no 'use client'
171
+ export default async function PostPage({
172
+ params,
173
+ }: {
174
+ params: Promise<{ id: string }> // params is a Promise in Next.js 15+
175
+ }) {
176
+ const { id } = await params
177
+ const post = await db.post.findUnique({ where: { id } })
178
+
179
+ return <article>{post.content}</article>
180
+ }
181
+ ```
182
+
183
+ **Next.js 15+**: `params`, `searchParams` are Promises — must `await` them.
184
+
185
+ ## Streaming with Suspense + loading.tsx
186
+
187
+ ```tsx
188
+ // app/posts/page.tsx
189
+ import { Suspense } from 'react'
190
+
191
+ export default function PostsPage() {
192
+ return (
193
+ <div>
194
+ <h1>Posts</h1>
195
+ <Suspense fallback={<PostsSkeleton />}>
196
+ <PostsList /> {/* Streams in when ready */}
197
+ </Suspense>
198
+ <Suspense fallback={<StatsSkeleton />}>
199
+ <PostStats /> {/* Streams independently */}
200
+ </Suspense>
201
+ </div>
202
+ )
203
+ }
204
+ ```
205
+
206
+ - `loading.tsx` wraps the entire page in Suspense automatically
207
+ - Manual `<Suspense>` gives finer control — stream sections independently
208
+ - Wrap data-fetching Server Components in Suspense
209
+
210
+ ## RSC Boundary Rules
211
+
212
+ ```
213
+ Server Component (default)
214
+ └─ can render → Client Components
215
+ └─ can pass → serializable props only (no functions, no JSX as props)
216
+ └─ can use → async/await, direct DB access, filesystem, secrets
217
+
218
+ Client Component ('use client')
219
+ └─ can render → Server Components (passed as children)
220
+ └─ can use → hooks, event handlers, browser APIs, state
221
+ └─ cannot → async/await directly, access DB
222
+ ```
223
+
224
+ **Boundary pattern** — push 'use client' as deep as possible:
225
+
226
+ ```tsx
227
+ // ✅ Server Component (default) — data fetching here
228
+ export default async function UserProfile({ userId }) {
229
+ const user = await db.user.findUnique({ where: { id: userId } })
230
+
231
+ return (
232
+ <div>
233
+ <h1>{user.name}</h1>
234
+ <EditButton /> {/* Only the interactive leaf is client */}
235
+ </div>
236
+ )
237
+ }
238
+
239
+ // ✅ Client leaf — only what needs interactivity
240
+ 'use client'
241
+ function EditButton() {
242
+ const [open, setOpen] = useState(false)
243
+ return <button onClick={() => setOpen(true)}>Edit</button>
244
+ }
245
+ ```
246
+
247
+ ## Error Handling
248
+
249
+ ```tsx
250
+ // app/dashboard/error.tsx
251
+ 'use client'
252
+
253
+ export default function DashboardError({
254
+ error,
255
+ reset,
256
+ }: {
257
+ error: Error & { digest?: string }
258
+ reset: () => void
259
+ }) {
260
+ return (
261
+ <div>
262
+ <h2>Something went wrong!</h2>
263
+ <button onClick={() => reset()}>Try again</button>
264
+ </div>
265
+ )
266
+ }
267
+ ```
268
+
269
+ - `error.tsx` must be a Client Component
270
+ - Errors bubble up to the nearest `error.tsx`
271
+ - `reset()` re-renders the error boundary's children
272
+ - `error.tsx` in a nested segment only catches errors in that segment and below
273
+
274
+ ## Middleware
275
+
276
+ ```tsx
277
+ // middleware.ts (root level)
278
+ import { NextResponse } from 'next/server'
279
+ import type { NextRequest } from 'next/server'
280
+
281
+ export function middleware(request: NextRequest) {
282
+ const token = request.cookies.get('token')
283
+
284
+ // Protect routes
285
+ if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
286
+ return NextResponse.redirect(new URL('/login', request.url))
287
+ }
288
+
289
+ return NextResponse.next()
290
+ }
291
+
292
+ export const config = {
293
+ matcher: ['/dashboard/:path*']
294
+ }
295
+ ```
296
+
297
+ ## Metadata API
298
+
299
+ ```tsx
300
+ // Static metadata
301
+ export const metadata: Metadata = {
302
+ title: 'Dashboard',
303
+ description: 'Manage your account',
304
+ }
305
+
306
+ // Dynamic metadata (Server Components)
307
+ export async function generateMetadata({ params }): Promise<Metadata> {
308
+ const post = await getPost(params.id)
309
+ return { title: post.title, description: post.excerpt }
310
+ }
311
+ ```
312
+
313
+ ## Common Pitfalls
314
+
315
+ | Pitfall | Fix |
316
+ |---------|-----|
317
+ | Adding `'use client'` to a layout | Layouts are Server Components by default; only add `'use client'` when you need hooks |
318
+ | Forgetting `default.tsx` for parallel routes | Every slot needs a `default.tsx` for initial load |
319
+ | Passing functions as props from Server to Client | Functions are not serializable — define them in the client |
320
+ | Using `useSearchParams()` in Server Component | Use `searchParams` prop (Promise in v15+) |
321
+ | `params` treated as plain object (v15+) | `params` is now a Promise — must `await params` |
322
+ | No Suspense boundary for async component | Wrap in `<Suspense>` or ensure `loading.tsx` exists |
323
+ | `layout.tsx` doesn't receive `searchParams` | Only `page.tsx` gets `searchParams` |
324
+
325
+ ## Verification
326
+
327
+ - [ ] Server Components are the default — `'use client'` only where interactive
328
+ - [ ] `params` and `searchParams` are awaited (Next.js 15+)
329
+ - [ ] Error boundaries (`error.tsx`) exist at appropriate levels
330
+ - [ ] Loading states (`loading.tsx` or `<Suspense>`) for async pages
331
+ - [ ] Parallel route slots each have `default.tsx`
332
+ - [ ] Layout and template used correctly (persist vs remount)
333
+ - [ ] Route groups used to share layouts without affecting URL
334
+ - [ ] Functions and non-serializable data stay in Client Components