tribunal-kit 3.0.0 → 4.0.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 (233) hide show
  1. package/.agent/ARCHITECTURE.md +99 -99
  2. package/.agent/GEMINI.md +52 -52
  3. package/.agent/agents/accessibility-reviewer.md +187 -220
  4. package/.agent/agents/ai-code-reviewer.md +199 -233
  5. package/.agent/agents/backend-specialist.md +215 -238
  6. package/.agent/agents/code-archaeologist.md +161 -181
  7. package/.agent/agents/database-architect.md +184 -207
  8. package/.agent/agents/debugger.md +191 -218
  9. package/.agent/agents/dependency-reviewer.md +103 -136
  10. package/.agent/agents/devops-engineer.md +218 -238
  11. package/.agent/agents/documentation-writer.md +201 -221
  12. package/.agent/agents/explorer-agent.md +160 -180
  13. package/.agent/agents/frontend-reviewer.md +160 -194
  14. package/.agent/agents/frontend-specialist.md +248 -237
  15. package/.agent/agents/game-developer.md +48 -52
  16. package/.agent/agents/logic-reviewer.md +116 -149
  17. package/.agent/agents/mobile-developer.md +200 -223
  18. package/.agent/agents/mobile-reviewer.md +162 -195
  19. package/.agent/agents/orchestrator.md +181 -211
  20. package/.agent/agents/penetration-tester.md +157 -174
  21. package/.agent/agents/performance-optimizer.md +183 -203
  22. package/.agent/agents/performance-reviewer.md +178 -211
  23. package/.agent/agents/precedence-reviewer.md +213 -0
  24. package/.agent/agents/product-manager.md +142 -162
  25. package/.agent/agents/product-owner.md +6 -25
  26. package/.agent/agents/project-planner.md +142 -162
  27. package/.agent/agents/qa-automation-engineer.md +225 -242
  28. package/.agent/agents/security-auditor.md +174 -194
  29. package/.agent/agents/seo-specialist.md +193 -213
  30. package/.agent/agents/sql-reviewer.md +161 -194
  31. package/.agent/agents/supervisor-agent.md +184 -203
  32. package/.agent/agents/swarm-worker-contracts.md +17 -17
  33. package/.agent/agents/swarm-worker-registry.md +46 -46
  34. package/.agent/agents/test-coverage-reviewer.md +160 -193
  35. package/.agent/agents/test-engineer.md +0 -21
  36. package/.agent/agents/type-safety-reviewer.md +175 -208
  37. package/.agent/patterns/generator.md +9 -9
  38. package/.agent/patterns/inversion.md +12 -12
  39. package/.agent/patterns/pipeline.md +9 -9
  40. package/.agent/patterns/reviewer.md +13 -13
  41. package/.agent/patterns/tool-wrapper.md +9 -9
  42. package/.agent/rules/GEMINI.md +63 -63
  43. package/.agent/scripts/append_flow.js +72 -0
  44. package/.agent/scripts/case_law_manager.py +525 -0
  45. package/.agent/scripts/compress_skills.py +167 -0
  46. package/.agent/scripts/consolidate_skills.py +173 -0
  47. package/.agent/scripts/deep_compress.py +202 -0
  48. package/.agent/scripts/minify_context.py +80 -0
  49. package/.agent/scripts/security_scan.py +1 -1
  50. package/.agent/scripts/skill_evolution.py +563 -0
  51. package/.agent/scripts/strip_tribunal.py +41 -0
  52. package/.agent/skills/agent-organizer/SKILL.md +100 -126
  53. package/.agent/skills/agentic-patterns/SKILL.md +0 -70
  54. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +134 -160
  55. package/.agent/skills/api-patterns/SKILL.md +123 -215
  56. package/.agent/skills/api-security-auditor/SKILL.md +143 -177
  57. package/.agent/skills/app-builder/SKILL.md +334 -50
  58. package/.agent/skills/app-builder/templates/SKILL.md +13 -15
  59. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +16 -16
  60. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +22 -22
  61. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +18 -18
  62. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +20 -20
  63. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +17 -17
  64. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +18 -18
  65. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +21 -21
  66. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +19 -19
  67. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +26 -26
  68. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +26 -26
  69. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +19 -19
  70. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +18 -18
  71. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +20 -20
  72. package/.agent/skills/appflow-wireframe/SKILL.md +95 -121
  73. package/.agent/skills/architecture/SKILL.md +169 -331
  74. package/.agent/skills/authentication-best-practices/SKILL.md +139 -173
  75. package/.agent/skills/bash-linux/SKILL.md +129 -154
  76. package/.agent/skills/behavioral-modes/SKILL.md +8 -69
  77. package/.agent/skills/brainstorming/SKILL.md +436 -104
  78. package/.agent/skills/building-native-ui/SKILL.md +152 -174
  79. package/.agent/skills/clean-code/SKILL.md +331 -360
  80. package/.agent/skills/code-review-checklist/SKILL.md +0 -62
  81. package/.agent/skills/config-validator/SKILL.md +115 -141
  82. package/.agent/skills/csharp-developer/SKILL.md +468 -528
  83. package/.agent/skills/database-design/SKILL.md +104 -369
  84. package/.agent/skills/deployment-procedures/SKILL.md +119 -145
  85. package/.agent/skills/devops-engineer/SKILL.md +295 -332
  86. package/.agent/skills/devops-incident-responder/SKILL.md +87 -113
  87. package/.agent/skills/doc.md +5 -5
  88. package/.agent/skills/documentation-templates/SKILL.md +27 -63
  89. package/.agent/skills/edge-computing/SKILL.md +131 -157
  90. package/.agent/skills/extract-design-system/SKILL.md +108 -134
  91. package/.agent/skills/framer-motion-expert/SKILL.md +111 -855
  92. package/.agent/skills/frontend-design/SKILL.md +151 -499
  93. package/.agent/skills/game-design-expert/SKILL.md +79 -105
  94. package/.agent/skills/game-engineering-expert/SKILL.md +96 -122
  95. package/.agent/skills/geo-fundamentals/SKILL.md +97 -124
  96. package/.agent/skills/github-operations/SKILL.md +279 -314
  97. package/.agent/skills/gsap-expert/SKILL.md +119 -826
  98. package/.agent/skills/i18n-localization/SKILL.md +113 -138
  99. package/.agent/skills/intelligent-routing/SKILL.md +167 -127
  100. package/.agent/skills/lint-and-validate/SKILL.md +16 -52
  101. package/.agent/skills/llm-engineering/SKILL.md +344 -357
  102. package/.agent/skills/local-first/SKILL.md +128 -154
  103. package/.agent/skills/mcp-builder/SKILL.md +92 -118
  104. package/.agent/skills/mobile-design/SKILL.md +213 -219
  105. package/.agent/skills/motion-engineering/SKILL.md +184 -0
  106. package/.agent/skills/nextjs-react-expert/SKILL.md +99 -698
  107. package/.agent/skills/nodejs-best-practices/SKILL.md +498 -559
  108. package/.agent/skills/observability/SKILL.md +293 -330
  109. package/.agent/skills/parallel-agents/SKILL.md +96 -122
  110. package/.agent/skills/performance-profiling/SKILL.md +217 -254
  111. package/.agent/skills/plan-writing/SKILL.md +92 -118
  112. package/.agent/skills/platform-engineer/SKILL.md +97 -123
  113. package/.agent/skills/playwright-best-practices/SKILL.md +137 -162
  114. package/.agent/skills/powershell-windows/SKILL.md +112 -146
  115. package/.agent/skills/project-idioms/SKILL.md +87 -0
  116. package/.agent/skills/python-patterns/SKILL.md +15 -35
  117. package/.agent/skills/python-pro/SKILL.md +148 -754
  118. package/.agent/skills/react-specialist/SKILL.md +123 -827
  119. package/.agent/skills/readme-builder/SKILL.md +23 -85
  120. package/.agent/skills/realtime-patterns/SKILL.md +269 -304
  121. package/.agent/skills/red-team-tactics/SKILL.md +18 -51
  122. package/.agent/skills/rust-pro/SKILL.md +623 -701
  123. package/.agent/skills/seo-fundamentals/SKILL.md +129 -154
  124. package/.agent/skills/server-management/SKILL.md +164 -190
  125. package/.agent/skills/shadcn-ui-expert/SKILL.md +181 -206
  126. package/.agent/skills/skill-creator/SKILL.md +24 -56
  127. package/.agent/skills/sql-pro/SKILL.md +579 -633
  128. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +35 -66
  129. package/.agent/skills/swiftui-expert/SKILL.md +151 -176
  130. package/.agent/skills/systematic-debugging/SKILL.md +92 -118
  131. package/.agent/skills/tailwind-patterns/SKILL.md +516 -576
  132. package/.agent/skills/tdd-workflow/SKILL.md +111 -137
  133. package/.agent/skills/test-result-analyzer/SKILL.md +33 -73
  134. package/.agent/skills/testing-patterns/SKILL.md +512 -573
  135. package/.agent/skills/trend-researcher/SKILL.md +30 -71
  136. package/.agent/skills/ui-ux-pro-max/SKILL.md +8 -41
  137. package/.agent/skills/ui-ux-researcher/SKILL.md +51 -91
  138. package/.agent/skills/vue-expert/SKILL.md +127 -866
  139. package/.agent/skills/vulnerability-scanner/SKILL.md +354 -269
  140. package/.agent/skills/web-accessibility-auditor/SKILL.md +168 -193
  141. package/.agent/skills/web-design-guidelines/SKILL.md +25 -61
  142. package/.agent/skills/webapp-testing/SKILL.md +119 -145
  143. package/.agent/skills/whimsy-injector/SKILL.md +58 -132
  144. package/.agent/skills/workflow-optimizer/SKILL.md +28 -68
  145. package/.agent/workflows/api-tester.md +151 -151
  146. package/.agent/workflows/audit.md +127 -138
  147. package/.agent/workflows/brainstorm.md +110 -110
  148. package/.agent/workflows/changelog.md +112 -112
  149. package/.agent/workflows/create.md +124 -124
  150. package/.agent/workflows/debug.md +165 -189
  151. package/.agent/workflows/deploy.md +180 -189
  152. package/.agent/workflows/enhance.md +128 -151
  153. package/.agent/workflows/fix.md +114 -135
  154. package/.agent/workflows/generate.md +13 -4
  155. package/.agent/workflows/migrate.md +160 -160
  156. package/.agent/workflows/orchestrate.md +168 -168
  157. package/.agent/workflows/performance-benchmarker.md +114 -123
  158. package/.agent/workflows/plan.md +173 -173
  159. package/.agent/workflows/preview.md +80 -80
  160. package/.agent/workflows/refactor.md +161 -183
  161. package/.agent/workflows/review-ai.md +101 -129
  162. package/.agent/workflows/review.md +116 -116
  163. package/.agent/workflows/session.md +94 -94
  164. package/.agent/workflows/status.md +79 -79
  165. package/.agent/workflows/strengthen-skills.md +138 -139
  166. package/.agent/workflows/swarm.md +179 -179
  167. package/.agent/workflows/test.md +189 -211
  168. package/.agent/workflows/tribunal-backend.md +94 -113
  169. package/.agent/workflows/tribunal-database.md +95 -115
  170. package/.agent/workflows/tribunal-frontend.md +96 -118
  171. package/.agent/workflows/tribunal-full.md +93 -133
  172. package/.agent/workflows/tribunal-mobile.md +95 -119
  173. package/.agent/workflows/tribunal-performance.md +110 -133
  174. package/.agent/workflows/ui-ux-pro-max.md +122 -143
  175. package/README.md +30 -1
  176. package/bin/tribunal-kit.js +175 -12
  177. package/package.json +25 -4
  178. package/.agent/skills/api-patterns/api-style.md +0 -42
  179. package/.agent/skills/api-patterns/auth.md +0 -24
  180. package/.agent/skills/api-patterns/documentation.md +0 -26
  181. package/.agent/skills/api-patterns/graphql.md +0 -41
  182. package/.agent/skills/api-patterns/rate-limiting.md +0 -31
  183. package/.agent/skills/api-patterns/response.md +0 -37
  184. package/.agent/skills/api-patterns/rest.md +0 -40
  185. package/.agent/skills/api-patterns/security-testing.md +0 -122
  186. package/.agent/skills/api-patterns/trpc.md +0 -41
  187. package/.agent/skills/api-patterns/versioning.md +0 -22
  188. package/.agent/skills/app-builder/agent-coordination.md +0 -71
  189. package/.agent/skills/app-builder/feature-building.md +0 -53
  190. package/.agent/skills/app-builder/project-detection.md +0 -34
  191. package/.agent/skills/app-builder/scaffolding.md +0 -118
  192. package/.agent/skills/app-builder/tech-stack.md +0 -40
  193. package/.agent/skills/architecture/context-discovery.md +0 -43
  194. package/.agent/skills/architecture/examples.md +0 -94
  195. package/.agent/skills/architecture/pattern-selection.md +0 -68
  196. package/.agent/skills/architecture/patterns-reference.md +0 -50
  197. package/.agent/skills/architecture/trade-off-analysis.md +0 -77
  198. package/.agent/skills/brainstorming/dynamic-questioning.md +0 -360
  199. package/.agent/skills/database-design/database-selection.md +0 -43
  200. package/.agent/skills/database-design/indexing.md +0 -39
  201. package/.agent/skills/database-design/migrations.md +0 -48
  202. package/.agent/skills/database-design/optimization.md +0 -36
  203. package/.agent/skills/database-design/orm-selection.md +0 -30
  204. package/.agent/skills/database-design/schema-design.md +0 -56
  205. package/.agent/skills/frontend-design/animation-guide.md +0 -331
  206. package/.agent/skills/frontend-design/color-system.md +0 -329
  207. package/.agent/skills/frontend-design/decision-trees.md +0 -418
  208. package/.agent/skills/frontend-design/motion-graphics.md +0 -306
  209. package/.agent/skills/frontend-design/typography-system.md +0 -363
  210. package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
  211. package/.agent/skills/frontend-design/visual-effects.md +0 -383
  212. package/.agent/skills/intelligent-routing/router-manifest.md +0 -65
  213. package/.agent/skills/mobile-design/decision-trees.md +0 -516
  214. package/.agent/skills/mobile-design/mobile-backend.md +0 -491
  215. package/.agent/skills/mobile-design/mobile-color-system.md +0 -420
  216. package/.agent/skills/mobile-design/mobile-debugging.md +0 -122
  217. package/.agent/skills/mobile-design/mobile-design-thinking.md +0 -357
  218. package/.agent/skills/mobile-design/mobile-navigation.md +0 -458
  219. package/.agent/skills/mobile-design/mobile-performance.md +0 -767
  220. package/.agent/skills/mobile-design/mobile-testing.md +0 -356
  221. package/.agent/skills/mobile-design/mobile-typography.md +0 -433
  222. package/.agent/skills/mobile-design/platform-android.md +0 -666
  223. package/.agent/skills/mobile-design/platform-ios.md +0 -561
  224. package/.agent/skills/mobile-design/touch-psychology.md +0 -537
  225. package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
  226. package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
  227. package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
  228. package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
  229. package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
  230. package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
  231. package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
  232. package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
  233. package/.agent/skills/vulnerability-scanner/checklists.md +0 -121
@@ -1,783 +1,184 @@
1
1
  ---
2
2
  name: nextjs-react-expert
3
- description: Next.js 15+ App Router mastery. Server Components, Server Actions, Streaming SSR, Partial Prerendering (PPR), route handlers, middleware, caching/revalidation, generateMetadata, parallel routes, intercepting routes, and AI streaming UI. Use when building Next.js applications, optimizing performance, eliminating waterfalls, or implementing App Router patterns.
3
+ description: Next.js 15+ App Router mastery. Server Components, Server Actions, PPR, caching, metadata, middleware, parallel/intercepting routes. Use when building Next.js apps or optimizing Next.js performance.
4
4
  allowed-tools: Read, Write, Edit, Glob, Grep
5
- version: 2.0.0
6
- last-updated: 2026-03-30
7
- applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
5
+ version: 3.1.0
6
+ last-updated: 2026-04-06
7
+ applies-to-model: gemini-3-1-pro, claude-3-7-sonnet
8
8
  ---
9
9
 
10
- # Next.js 15+ App Router — Pro-Max Patterns
10
+ # Next.js 15+ App Router — Dense Reference
11
11
 
12
- > The fastest code is code that doesn't run on the client.
13
- > The second fastest is code that runs on the edge and streams the result.
14
- > If you're using `getServerSideProps`, `getStaticProps`, or the Pages Router you're writing legacy.
12
+ ## Hallucination Traps (Read First)
13
+ - `pages/api/` or `_app.tsx` App Router only: `app/api/route.ts`, `app/layout.tsx`
14
+ - `getServerSideProps` `async function Page()` fetches directly
15
+ - ❌ `next/router` → ✅ `next/navigation` (`useRouter`, `usePathname`, `useSearchParams`)
16
+ - ❌ Server Action without `"use server"` → ✅ Required at top of file or top of function
17
+ - ❌ Fetch is cached by default → ✅ **Next.js 15 changed this**: `fetch()` is UNCACHED by default
18
+ - ❌ `cookies()` at top of page → ✅ Opts entire route into dynamic rendering, breaking PPR. Wrap inside `<Suspense>`
19
+ - ❌ Passing functions as props Server → Client → ✅ Illegal. Use Server Actions instead.
20
+ - ❌ Plain `Response` in route handler → ✅ Use `NextResponse.json()`
15
21
 
16
22
  ---
17
23
 
18
- ## Paradigm Shifts (Next.js 14 → 15+)
24
+ ## App Router Conventions
19
25
 
20
- | Legacy (Pages Router / Next 14) | Modern (App Router / Next 15+) |
21
- |---|---|
22
- | `getServerSideProps` / `getStaticProps` | **Server Components** fetch directly |
23
- | Manual `useMemo()` / `useCallback()` | **React Compiler** handles memoization |
24
- | Client-side form handling | **Server Actions** native mutations |
25
- | Loading spinners on client | **Streaming UI** + `<Suspense>` boundaries |
26
- | Static *or* Dynamic pages | **Partial Prerendering (PPR)** — both in one route |
27
- | `next/router` (`useRouter`) | `next/navigation` (`useRouter`, `usePathname`, `useSearchParams`) |
28
-
29
- ---
30
-
31
- ## App Router File Conventions
32
-
33
- ```
26
+ ```text
34
27
  app/
35
- ├── layout.tsx ← Root layout (wraps ALL routes)
36
- ├── page.tsx Home page (/)
37
- ├── loading.tsx Automatic <Suspense> fallback for the route
38
- ├── error.tsx ← Error boundary for the route
39
- ├── not-found.tsx ← 404 page
40
- ├── global-error.tsx ← Root error boundary (wraps layout)
41
-
42
- ├── dashboard/
43
- │ ├── layout.tsx Dashboard layout (persists across sub-routes)
44
- │ ├── page.tsx ← /dashboard
45
- │ ├── loading.tsx ← Dashboard loading state
46
- │ ├── error.tsx ← Dashboard error boundary
47
- │ │
48
- │ ├── settings/
49
- │ │ └── page.tsx ← /dashboard/settings
50
- │ │
51
- │ └── [userId]/ ← Dynamic segment
52
- │ └── page.tsx ← /dashboard/abc123
53
-
54
- ├── api/
55
- │ └── users/
56
- │ └── route.ts ← API Route Handler (GET, POST, etc.)
57
-
58
- ├── @modal/ ← Parallel route (named slot)
59
- │ └── login/
60
- │ └── page.tsx ← Rendered in parallel with main content
61
-
62
- └── (marketing)/ ← Route group (no URL impact — for layout organization)
63
- ├── layout.tsx ← Layout ONLY for marketing pages
64
- ├── about/
65
- │ └── page.tsx ← /about (NOT /marketing/about)
66
- └── pricing/
67
- └── page.tsx ← /pricing
68
- ```
69
-
70
- ```tsx
71
- // ❌ HALLUCINATION TRAP: These Pages Router files DO NOT EXIST in App Router
72
- // _app.tsx → use app/layout.tsx
73
- // _document.tsx → use app/layout.tsx with <html> and <body>
74
- // pages/api/ → use app/api/route.ts
75
- // getServerSideProps → fetch directly in Server Components
76
- // getStaticProps → fetch at build time or use generateStaticParams
28
+ ├── layout.tsx ← Root shell (HTML/BODY)
29
+ ├── page.tsx Route UI
30
+ ├── loading.tsx Auto-suspense fallback
31
+ ├── error.tsx ← Error boundary (Must be "use client")
32
+ ├── not-found.tsx ← 404 UI
33
+ ├── global-error.tsx ← Root error boundary
34
+ ├── api/users/route.ts ← API Handler (GET, POST)
35
+ ├── @modal/login/page.tsx ← Parallel Route (renders in same layout)
36
+ └── (auth)/login/page.tsx Route Group (doesn't affect URL)
77
37
  ```
78
38
 
79
39
  ---
80
40
 
81
41
  ## Server vs Client Components
82
42
 
83
- ### The Decision
84
-
85
- ```
86
- Default: Server Component (Zero JS sent to client)
87
- Switch to Client ('use client') ONLY when:
88
- ✓ Uses browser APIs (window, localStorage, navigator, IntersectionObserver)
89
- ✓ Needs DOM event handlers (onClick, onChange, onSubmit)
90
- ✓ Needs state/effects (useState, useEffect, useRef for DOM)
91
- ✓ Needs Framer Motion, GSAP, or client-side animation libraries
92
-
93
- Everything else stays on the server.
94
- ```
95
-
96
- ### The Interleaving Pattern
43
+ - **Server Components (Default)**: Zero JS. Direct DB access. Secure env vars.
44
+ - **Client Components (`"use client"`)**: Lifecycle (`useEffect`), State (`useState`), Browser APIs (`window`), Event listeners (`onClick`).
97
45
 
98
46
  ```tsx
99
- // ✅ CORRECT: Keep the shell on the server, pass server content INTO client
100
- // app/dashboard/page.tsx (Server Component)
101
- import { ClientSidebar } from "./ClientSidebar";
102
- import { ServerStats } from "./ServerStats"; // fetches DB directly
103
-
104
- export default async function DashboardPage() {
105
- const stats = await getStats(); // no API call needed — direct DB
106
-
47
+ // ✅ INTERLEAVING PATTERN: Pass Server Component as children to Client Component
48
+ export default function Page() {
107
49
  return (
108
- <div className="flex">
109
- <ClientSidebar> {/* client: has onClick, state */}
110
- <ServerStats data={stats} /> {/* server: zero JS, renders HTML */}
111
- </ClientSidebar>
112
- </div>
50
+ <ClientSidebar> {/* "use client" */}
51
+ <ServerStats /> {/* Server: zero JS bundle, fetches DB */}
52
+ </ClientSidebar>
113
53
  );
114
54
  }
115
-
116
- // ❌ WRONG: Making the entire page "use client" because one button needs onClick
117
- // This ships ALL the JS to the client — defeats the purpose of RSC
118
- ```
119
-
120
- ### Serialization Boundary
121
-
122
- ```tsx
123
- // Only serializable data can cross the server→client boundary
124
- // ✅ Can pass: strings, numbers, booleans, arrays, plain objects, Date, Map, Set
125
- // ❌ Cannot pass: functions, class instances, DOM nodes, Symbols
126
-
127
- // ❌ BAD: Passing a function from server to client
128
- <ClientButton onClick={() => deleteItem(id)} /> // functions aren't serializable
129
-
130
- // ✅ GOOD: Use a Server Action instead
131
- <ClientButton deleteAction={deleteItemAction} itemId={id} />
132
-
133
- // In ClientButton:
134
- "use client";
135
- function ClientButton({ deleteAction, itemId }) {
136
- return <button onClick={() => deleteAction(itemId)}>Delete</button>;
137
- }
138
55
  ```
139
56
 
140
57
  ---
141
58
 
142
- ## Server Actions
59
+ ## Server Actions (Mutations)
143
60
 
144
61
  ```tsx
145
- // Server Actions are async functions that run on the server
146
- // They can be called from client or server components
147
-
148
- // ✅ Inline Server Action (defined in a Server Component)
149
- export default function Page() {
150
- async function createUser(formData: FormData) {
151
- "use server"; // marks this function as a Server Action
152
-
153
- const name = formData.get("name") as string;
154
- const email = formData.get("email") as string;
155
-
156
- await db.user.create({ data: { name, email } });
157
- revalidatePath("/users"); // bust cache for /users
158
- redirect("/users"); // redirect after mutation
159
- }
160
-
161
- return (
162
- <form action={createUser}>
163
- <input name="name" required />
164
- <input name="email" type="email" required />
165
- <button type="submit">Create</button>
166
- </form>
167
- );
168
- }
169
- ```
170
-
171
- ### Separate Action File
172
-
173
- ```tsx
174
- // app/actions/user.ts
175
- "use server";
176
-
62
+ "use server"
177
63
  import { revalidatePath } from "next/cache";
178
- import { redirect } from "next/navigation";
179
64
  import { z } from "zod";
180
65
 
181
- const UserSchema = z.object({
182
- name: z.string().min(2),
183
- email: z.string().email(),
184
- });
66
+ const Schema = z.object({ name: z.string().min(2) });
185
67
 
186
68
  export async function createUser(prevState: any, formData: FormData) {
187
- const parsed = UserSchema.safeParse({
188
- name: formData.get("name"),
189
- email: formData.get("email"),
190
- });
191
-
192
- if (!parsed.success) {
193
- return { errors: parsed.error.flatten().fieldErrors };
194
- }
195
-
196
- try {
197
- await db.user.create({ data: parsed.data });
198
- } catch (e) {
199
- return { errors: { _form: ["Failed to create user"] } };
200
- }
201
-
202
- revalidatePath("/users");
203
- redirect("/users");
69
+ // TRAP: ALWAYS validate formData. Never trust client input.
70
+ const parsed = Schema.safeParse({ name: formData.get("name") });
71
+ if (!parsed.success) return { errors: parsed.error.flatten().fieldErrors };
72
+
73
+ await db.user.create({ data: parsed.data });
74
+ revalidatePath("/users"); // Clears cache so next render shows new user
75
+ return { success: true };
204
76
  }
205
-
206
- // ❌ HALLUCINATION TRAP: Server Actions MUST be in a file with "use server"
207
- // at the top, OR defined inline with "use server" inside the function body.
208
- // They CANNOT be imported from a regular module.
209
-
210
- // ❌ HALLUCINATION TRAP: Always validate input in Server Actions.
211
- // FormData comes from the client — it's user input. Never trust it.
212
77
  ```
213
78
 
214
- ---
215
-
216
- ## Data Fetching & Caching
217
-
218
- ### Fetching in Server Components
219
-
79
+ Client usage (React 19):
220
80
  ```tsx
221
- // Server Components can fetch data directly — no useEffect, no API route
222
- export default async function UsersPage() {
223
- const users = await db.user.findMany(); // direct DB call
224
- // OR
225
- const res = await fetch("https://api.example.com/users", {
226
- next: { revalidate: 3600 }, // ISR: revalidate every hour
227
- });
228
- const users = await res.json();
229
-
230
- return <UserList users={users} />;
81
+ "use client"
82
+ import { useActionState } from "react";
83
+ import { createUser } from "./actions";
84
+
85
+ export function UserForm() {
86
+ const [state, formAction, isPending] = useActionState(createUser, null);
87
+ return (
88
+ <form action={formAction}>
89
+ <input name="name" />
90
+ <button disabled={isPending}>Submit</button>
91
+ {state?.errors?.name && <p>{state.errors.name}</p>}
92
+ </form>
93
+ )
231
94
  }
232
95
  ```
233
96
 
234
- ### Caching Strategies
235
-
236
- ```tsx
237
- // 1. Static (cached forever until revalidated)
238
- const data = await fetch(url); // default: cached
239
-
240
- // 2. ISR (Incremental Static Regeneration)
241
- const data = await fetch(url, {
242
- next: { revalidate: 60 }, // revalidate every 60 seconds
243
- });
244
-
245
- // 3. Dynamic (never cached)
246
- const data = await fetch(url, { cache: "no-store" });
247
-
248
- // 4. On-demand revalidation (Server Actions / Webhooks)
249
- import { revalidatePath, revalidateTag } from "next/cache";
250
-
251
- // Revalidate a specific path
252
- revalidatePath("/dashboard");
253
-
254
- // Revalidate by tag
255
- const data = await fetch(url, { next: { tags: ["users"] } });
256
- // Later, in a Server Action:
257
- revalidateTag("users"); // busts all fetches tagged "users"
258
-
259
- // ❌ HALLUCINATION TRAP: Next.js 15 changed the default caching behavior
260
- // In Next.js 14: fetch was cached by default
261
- // In Next.js 15: fetch is NOT cached by default (dynamic by default)
262
- // You must explicitly opt into caching with next.revalidate or cache: "force-cache"
263
- ```
97
+ ---
264
98
 
265
- ### `unstable_cache` for Non-Fetch Data
99
+ ## Data Fetching & Caching (Next.js 15)
266
100
 
267
101
  ```tsx
268
- import { unstable_cache } from "next/cache";
102
+ // Next.js 15 caching defaults
103
+ const dynamic = await fetch(url); // 15 default: NO CACHE
104
+ const static = await fetch(url, { cache: "force-cache" }); // Static
105
+ const isr = await fetch(url, { next: { revalidate: 3600 } }); // Revalidate every hour
106
+ const tagged = await fetch(url, { next: { tags: ["user-1"] } }); // On-demand via revalidateTag()
269
107
 
270
- // Cache database queries that don't use fetch()
108
+ // DB calls without fetch
109
+ import { unstable_cache } from "next/cache";
271
110
  const getCachedUser = unstable_cache(
272
- async (userId: string) => {
273
- return await db.user.findUnique({ where: { id: userId } });
274
- },
275
- ["user-by-id"], // cache key parts
276
- {
277
- revalidate: 3600, // 1 hour
278
- tags: ["user"], // for on-demand revalidation
279
- }
111
+ async (id) => db.user.findUnique({ where: { id } }),
112
+ ["user-cache-key"],
113
+ { revalidate: 60, tags: ["users"] }
280
114
  );
281
-
282
- // Usage:
283
- const user = await getCachedUser("abc123");
284
- ```
285
-
286
- ---
287
-
288
- ## Waterfall Elimination
289
-
290
- ### The Problem
291
-
292
- ```tsx
293
- // ❌ CRITICAL WATERFALL: Each await blocks the next
294
- async function Dashboard() {
295
- const user = await getUser(); // 200ms
296
- const posts = await getPosts(); // 200ms (waits for user)
297
- const analytics = await getAnalytics(); // 200ms (waits for posts)
298
- // Total: 600ms sequential
299
- }
300
115
  ```
301
116
 
302
- ### Fix 1: Parallel Fetching
303
-
117
+ ### Waterfall Elimination
304
118
  ```tsx
305
- // ✅ All three start simultaneously
306
- async function Dashboard() {
307
- const [user, posts, analytics] = await Promise.all([
308
- getUser(),
309
- getPosts(),
310
- getAnalytics(),
311
- ]);
312
- // Total: ~200ms (time of slowest call)
313
- }
314
- ```
315
-
316
- ### Fix 2: Streaming with Suspense (Pro-Max)
119
+ // ✅ Parallel Fetching:
120
+ const [user, posts] = await Promise.all([getUser(), getPosts()]);
317
121
 
318
- ```tsx
319
- // 🚀 Show fast content immediately, stream slow content later
320
- export default function Dashboard() {
122
+ // ✅ Streaming (PPR-compatible):
123
+ export default function Page() {
321
124
  return (
322
125
  <main>
323
- <FastHeader /> {/* renders instantly — static */}
324
-
325
- <Suspense fallback={<StatsSkeleton />}>
326
- <SlowStatsPanel /> {/* streams when DB resolves */}
327
- </Suspense>
328
-
329
- <Suspense fallback={<ChartSkeleton />}>
330
- <VerySlowChart /> {/* streams when API resolves */}
126
+ <FastNav />
127
+ {/* Page shell loads instantly, SlowChart streams in when ready */}
128
+ <Suspense fallback={<Skeleton />}>
129
+ <SlowChart />
331
130
  </Suspense>
332
131
  </main>
333
132
  );
334
133
  }
335
-
336
- // Each Suspense boundary independently streams its content
337
- // The user sees the page progressively — not a blank screen
338
134
  ```
339
135
 
340
136
  ---
341
137
 
342
138
  ## Partial Prerendering (PPR)
343
139
 
140
+ PPR static-generates the route shell and streams dynamic parts.
344
141
  ```tsx
345
142
  // next.config.ts
346
- export default {
347
- experimental: {
348
- ppr: true, // Enable Partial Prerendering
349
- },
350
- };
143
+ export default { experimental: { ppr: true } };
351
144
 
352
- // PPR = Static shell (edge-cached) + Dynamic holes (streamed)
353
- // The static parts are served from CDN at edge speed
354
- // Dynamic parts stream in from the server
145
+ // Any component reading cookies/headers inside a Suspense boundary becomes a dynamic hole
146
+ import { cookies } from "next/headers";
355
147
 
356
- export default function ProductPage({ params }: { params: { id: string } }) {
357
- return (
358
- <main>
359
- {/* 🟢 STATIC — pre-rendered at build time, served from CDN */}
360
- <Header />
361
- <ProductDetails id={params.id} />
148
+ async function Cart() {
149
+ const c = await cookies(); // Next.js 15 cookies are async!
150
+ const cartId = c.get("cartId");
151
+ }
362
152
 
363
- {/* 🔴 DYNAMIC — streamed on request (requires cookies/headers) */}
153
+ export default function Page() {
154
+ return (
155
+ <div>
156
+ <StaticHeader /> {/* Cached at build time on CDN */}
364
157
  <Suspense fallback={<CartSkeleton />}>
365
- <PersonalizedCart /> {/* reads cookies() dynamic */}
158
+ <Cart /> {/* Dynamic, streamed at request time */}
366
159
  </Suspense>
367
-
368
- <Suspense fallback={<ReviewsSkeleton />}>
369
- <LiveReviews /> {/* real-time data — dynamic */}
370
- </Suspense>
371
- </main>
372
- );
373
- }
374
-
375
- // ❌ HALLUCINATION TRAP: Using cookies(), headers(), or searchParams at the
376
- // top level of a component tree forces the ENTIRE route to be dynamic.
377
- // Isolate dynamic data inside Suspense boundaries for PPR to work.
378
- ```
379
-
380
- ---
381
-
382
- ## Metadata & SEO
383
-
384
- ### `generateMetadata` (Dynamic)
385
-
386
- ```tsx
387
- import { Metadata } from "next";
388
-
389
- // Static metadata
390
- export const metadata: Metadata = {
391
- title: "My App",
392
- description: "The best app ever",
393
- openGraph: { title: "My App", description: "...", images: ["/og.png"] },
394
- };
395
-
396
- // Dynamic metadata (based on params/data)
397
- export async function generateMetadata({
398
- params,
399
- }: {
400
- params: { slug: string };
401
- }): Promise<Metadata> {
402
- const post = await getPost(params.slug);
403
-
404
- return {
405
- title: post.title,
406
- description: post.excerpt,
407
- openGraph: {
408
- title: post.title,
409
- description: post.excerpt,
410
- images: [post.coverImage],
411
- },
412
- twitter: {
413
- card: "summary_large_image",
414
- title: post.title,
415
- },
416
- alternates: {
417
- canonical: `https://example.com/blog/${params.slug}`,
418
- },
419
- };
420
- }
421
-
422
- // ❌ HALLUCINATION TRAP: generateMetadata is an async function exported
423
- // from page.tsx or layout.tsx — NOT a React component.
424
- // It runs on the server during rendering.
425
- ```
426
-
427
- ### `generateStaticParams` (Static Generation)
428
-
429
- ```tsx
430
- // Pre-generate pages at build time (SSG)
431
- export async function generateStaticParams() {
432
- const posts = await getAllPosts();
433
-
434
- return posts.map((post) => ({
435
- slug: post.slug, // matches [slug] dynamic segment
436
- }));
437
- }
438
-
439
- // Combined with dynamicParams:
440
- export const dynamicParams = false; // 404 for unknown slugs
441
- // OR
442
- export const dynamicParams = true; // generate on-demand (default)
443
- ```
444
-
445
- ---
446
-
447
- ## Route Handlers (API Routes)
448
-
449
- ```tsx
450
- // app/api/users/route.ts
451
- import { NextRequest, NextResponse } from "next/server";
452
-
453
- export async function GET(request: NextRequest) {
454
- const searchParams = request.nextUrl.searchParams;
455
- const page = searchParams.get("page") ?? "1";
456
-
457
- const users = await db.user.findMany({
458
- skip: (parseInt(page) - 1) * 20,
459
- take: 20,
460
- });
461
-
462
- return NextResponse.json(users);
463
- }
464
-
465
- export async function POST(request: NextRequest) {
466
- const body = await request.json();
467
-
468
- // Always validate input
469
- const parsed = UserSchema.safeParse(body);
470
- if (!parsed.success) {
471
- return NextResponse.json(
472
- { error: parsed.error.flatten() },
473
- { status: 400 }
474
- );
475
- }
476
-
477
- const user = await db.user.create({ data: parsed.data });
478
- return NextResponse.json(user, { status: 201 });
479
- }
480
-
481
- // Dynamic route: app/api/users/[id]/route.ts
482
- export async function GET(
483
- request: NextRequest,
484
- { params }: { params: { id: string } }
485
- ) {
486
- const user = await db.user.findUnique({ where: { id: params.id } });
487
- if (!user) {
488
- return NextResponse.json({ error: "Not found" }, { status: 404 });
489
- }
490
- return NextResponse.json(user);
160
+ </div>
161
+ )
491
162
  }
492
-
493
- // ❌ HALLUCINATION TRAP: Route handlers use named exports (GET, POST, PUT, DELETE)
494
- // NOT default export. NOT export function handler().
495
- // ❌ HALLUCINATION TRAP: Route handlers are in route.ts, NOT in page.tsx
496
- // A directory cannot have both page.tsx and route.ts
497
163
  ```
498
164
 
499
165
  ---
500
166
 
501
167
  ## Middleware
502
168
 
503
- ```tsx
504
- // middleware.ts (in project ROOT, not inside app/)
169
+ ```typescript
170
+ // middleware.ts (Root of project)
505
171
  import { NextResponse } from "next/server";
506
172
  import type { NextRequest } from "next/server";
507
173
 
508
- export function middleware(request: NextRequest) {
509
- const token = request.cookies.get("session")?.value;
510
- const { pathname } = request.nextUrl;
511
-
512
- // Redirect unauthenticated users
513
- if (pathname.startsWith("/dashboard") && !token) {
514
- return NextResponse.redirect(new URL("/login", request.url));
174
+ export function middleware(req: NextRequest) {
175
+ const token = req.cookies.get("auth-token");
176
+ if (!token && req.nextUrl.pathname.startsWith("/dashboard")) {
177
+ return NextResponse.redirect(new URL("/login", req.url));
515
178
  }
516
-
517
- // Add custom headers
518
- const response = NextResponse.next();
519
- response.headers.set("x-pathname", pathname);
520
-
521
- return response;
522
179
  }
523
180
 
524
- // Matcher: only run middleware on specific routes
525
181
  export const config = {
526
- matcher: [
527
- "/dashboard/:path*",
528
- "/api/:path*",
529
- // Skip static files and Next.js internals
530
- "/((?!_next/static|_next/image|favicon.ico).*)",
531
- ],
182
+ matcher: ["/dashboard/:path*"], // Strict matcher is critical for performance
532
183
  };
533
-
534
- // ❌ HALLUCINATION TRAP: middleware.ts must be at the project ROOT
535
- // (same level as app/ directory), NOT inside app/
536
- // ❌ HALLUCINATION TRAP: Middleware runs on the Edge Runtime
537
- // You CANNOT use Node.js APIs (fs, crypto.createHash, etc.)
538
- // Use Web APIs (crypto.subtle, fetch, Response, Headers)
539
- ```
540
-
541
- ---
542
-
543
- ## Parallel & Intercepting Routes
544
-
545
- ### Parallel Routes (Named Slots)
546
-
547
- ```
548
- app/
549
- ├── layout.tsx
550
- ├── page.tsx
551
- ├── @analytics/
552
- │ └── page.tsx ← Rendered in parallel with main page
553
- └── @notifications/
554
- └── page.tsx ← Also rendered in parallel
555
- ```
556
-
557
- ```tsx
558
- // app/layout.tsx
559
- export default function Layout({
560
- children,
561
- analytics,
562
- notifications,
563
- }: {
564
- children: React.ReactNode;
565
- analytics: React.ReactNode;
566
- notifications: React.ReactNode;
567
- }) {
568
- return (
569
- <div>
570
- <main>{children}</main>
571
- <aside>{analytics}</aside>
572
- <div>{notifications}</div>
573
- </div>
574
- );
575
- }
576
- ```
577
-
578
- ### Intercepting Routes (Modal Pattern)
579
-
580
- ```
581
- app/
582
- ├── feed/
583
- │ └── page.tsx ← /feed (shows feed)
584
- ├── photo/[id]/
585
- │ └── page.tsx ← /photo/123 (full photo page)
586
- └── @modal/
587
- └── (..)photo/[id]/
588
- └── page.tsx ← Intercepts /photo/123 when navigating from /feed
589
- Shows as modal overlay instead of full page
590
- ```
591
-
592
184
  ```
593
- Intercepting conventions:
594
- (.) — same level
595
- (..) — one level up
596
- (..)(..) — two levels up
597
- (...) — from root
598
- ```
599
-
600
- ---
601
-
602
- ## AI & Streaming UI
603
-
604
- ```tsx
605
- import { openai } from "@ai-sdk/openai";
606
- import { streamText } from "ai";
607
-
608
- // app/api/chat/route.ts
609
- export async function POST(req: NextRequest) {
610
- const { messages } = await req.json();
611
-
612
- const result = streamText({
613
- model: openai("gpt-4o"),
614
- messages,
615
- });
616
-
617
- return result.toDataStreamResponse();
618
- }
619
-
620
- // Client component:
621
- "use client";
622
- import { useChat } from "@ai-sdk/react";
623
-
624
- function ChatUI() {
625
- const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
626
-
627
- return (
628
- <div>
629
- {messages.map((m) => (
630
- <div key={m.id} className={m.role === "user" ? "user" : "ai"}>
631
- {m.content}
632
- </div>
633
- ))}
634
- <form onSubmit={handleSubmit}>
635
- <input value={input} onChange={handleInputChange} />
636
- <button disabled={isLoading}>Send</button>
637
- </form>
638
- </div>
639
- );
640
- }
641
-
642
- // ❌ HALLUCINATION TRAP: Import from "@ai-sdk/react", NOT "ai/react"
643
- // The package was restructured in Vercel AI SDK 4+
644
- ```
645
-
646
- ---
647
-
648
- ## Bundle Optimization
649
-
650
- ```tsx
651
- // 1. Push "use client" as FAR DOWN as possible
652
- // ❌ BAD: "use client" on layout.tsx (ships entire layout as JS)
653
- // ✅ GOOD: "use client" only on the interactive widget component
654
-
655
- // 2. Dynamic imports for heavy client deps
656
- import dynamic from "next/dynamic";
657
-
658
- const HeavyChart = dynamic(() => import("./HeavyChart"), {
659
- ssr: false, // skip server rendering
660
- loading: () => <ChartSkeleton />,
661
- });
662
-
663
- // 3. next/image for automatic optimization
664
- import Image from "next/image";
665
-
666
- <Image
667
- src="/hero.jpg"
668
- alt="Hero image"
669
- width={1200}
670
- height={630}
671
- priority // preload for LCP images
672
- placeholder="blur"
673
- blurDataURL={blurUrl}
674
- />
675
-
676
- // 4. next/font for zero-layout-shift fonts
677
- import { Inter } from "next/font/google";
678
-
679
- const inter = Inter({
680
- subsets: ["latin"],
681
- display: "swap",
682
- variable: "--font-inter",
683
- });
684
-
685
- // In layout.tsx:
686
- <html className={inter.variable}>
687
- <body>{children}</body>
688
- </html>
689
-
690
- // ❌ HALLUCINATION TRAP: next/font automatically self-hosts fonts
691
- // Do NOT add Google Fonts <link> tags in <head> — they cause CLS
692
- ```
693
-
694
- ---
695
-
696
- ## Key Anti-Patterns
697
-
698
- | Pattern | Problem | Fix |
699
- |---|---|---|
700
- | `getServerSideProps` in App Router | Pages Router API — doesn't exist | Fetch directly in Server Components |
701
- | `"use client"` on layout/page | Ships massive JS bundle | Push `"use client"` to leaf components |
702
- | `useEffect(() => fetch(...))` | Client waterfall, no cache, CLS | Server Component or React Query |
703
- | Sequential `await` calls | Network waterfall | `Promise.all()` or `<Suspense>` |
704
- | `cookies()`/`headers()` at top level | Disables PPR for entire route | Isolate inside `<Suspense>` boundaries |
705
- | `next/router` (Pages Router) | Wrong import | Use `next/navigation` |
706
- | Missing `loading.tsx` | Blank screen during navigation | Add loading.tsx or Suspense |
707
- | Raw `<img>` and `<a>` tags | No optimization | Use `next/image` and `next/link` |
708
-
709
- ---
710
-
711
- ## Output Format
712
-
713
- When this skill produces or reviews code, structure your output as follows:
714
-
715
- ```
716
- ━━━ Next.js Expert Report ━━━━━━━━━━━━━━━━━━━━━━━━
717
- Skill: Next.js React Expert
718
- Next.js Ver: 15+
719
- Scope: [N files · N routes]
720
- ─────────────────────────────────────────────────
721
- ✅ Passed: [checks that passed, or "All clean"]
722
- ⚠️ Warnings: [non-blocking issues, or "None"]
723
- ❌ Blocked: [blocking issues requiring fix, or "None"]
724
- ─────────────────────────────────────────────────
725
- VBC status: PENDING → VERIFIED
726
- Evidence: [test output / lint pass / compile success]
727
- ```
728
-
729
- **VBC (Verification-Before-Completion) is mandatory.**
730
- Do not mark status as VERIFIED until concrete terminal evidence is provided.
731
-
732
- ---
733
-
734
- ## 🤖 LLM-Specific Traps
735
-
736
- AI coding assistants often fall into specific bad habits when generating Next.js code. These are strictly forbidden:
737
-
738
- 1. **Pages Router in App Router:** Never generate `getServerSideProps`, `getStaticProps`, `getInitialProps`, `_app.tsx`, `_document.tsx`, or `pages/api/` in an App Router project.
739
- 2. **`"use client"` Everywhere:** Marking layouts, pages, or entire feature modules as client components defeats RSC. Push the `"use client"` boundary as deep as possible.
740
- 3. **`next/router` Import:** The Pages Router `useRouter` is `next/router`. App Router uses `next/navigation`. Using the wrong one causes runtime errors.
741
- 4. **Missing Input Validation in Server Actions:** Server Actions receive raw `FormData` from the client. Always validate with Zod or similar before touching the database.
742
- 5. **`useEffect` for Data Fetching:** Server Components can fetch directly. Client components should use React Query or SWR. `useEffect` fetch has no caching, no deduplication, no error boundaries.
743
- 6. **Forgetting Next.js 15 Cache Changes:** In Next.js 15, `fetch()` is NOT cached by default (changed from 14). You must explicitly opt into caching.
744
- 7. **Google Fonts `<link>` Tags:** Never add external font `<link>` tags. Use `next/font` for zero-CLS, self-hosted fonts.
745
- 8. **Route Handler Default Exports:** Route handlers use named exports (`GET`, `POST`, `DELETE`), not `export default function handler`.
746
- 9. **Middleware Inside `app/`:** `middleware.ts` must be at the project root, not inside the `app/` directory.
747
- 10. **`"ai/react"` Import Path:** The Vercel AI SDK restructured its exports. Use `@ai-sdk/react` for hooks and `ai` for core.
748
-
749
- ---
750
-
751
- ## 🏛️ Tribunal Integration (Anti-Hallucination)
752
-
753
- **Slash command: `/tribunal-frontend`**
754
- **Active reviewers: `logic` · `security` · `frontend` · `type-safety`**
755
-
756
- ### ❌ Forbidden AI Tropes
757
-
758
- 1. **Blind Assumptions:** Never make an assumption without documenting it clearly with `// VERIFY: [reason]`.
759
- 2. **Silent Degradation:** Catching and suppressing errors without logging or displaying error boundaries.
760
- 3. **Context Amnesia:** Forgetting whether the project uses Pages Router or App Router.
761
- 4. **Generic Design:** Do not default to black/white Vercel aesthetics unless instructed.
762
-
763
- ### ✅ Pre-Flight Self-Audit
764
-
765
- Review these questions before confirming output:
766
- ```
767
- ✅ Did I maximize Server Component usage and isolate "use client"?
768
- ✅ Are there sequential awaits creating a waterfall? Did I use Promise.all or Suspense?
769
- ✅ Did I validate all Server Action inputs with Zod?
770
- ✅ Did I use next/image and next/link (not raw <img> and <a>)?
771
- ✅ Did I implement loading.tsx and error.tsx for route segments?
772
- ✅ Did I use next/font (not external font <link> tags)?
773
- ✅ Did I use next/navigation (not next/router)?
774
- ✅ Are dynamic data reads (cookies, headers) inside Suspense for PPR?
775
- ✅ Did I add generateMetadata for SEO?
776
- ✅ Is middleware.ts at the project root (not inside app/)?
777
- ```
778
-
779
- ### 🛑 Verification-Before-Completion (VBC) Protocol
780
-
781
- **CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
782
- - ❌ **Forbidden:** Assuming a Next.js route "works" because the dev server shows no errors.
783
- - ✅ **Required:** You are explicitly forbidden from completing your task without providing **concrete evidence** (successful `next build`, passing tests, or equivalent proof) that the code compiles and runs correctly.