tribunal-kit 2.4.6 → 3.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 (142) hide show
  1. package/.agent/agents/accessibility-reviewer.md +220 -134
  2. package/.agent/agents/ai-code-reviewer.md +233 -129
  3. package/.agent/agents/backend-specialist.md +238 -178
  4. package/.agent/agents/code-archaeologist.md +181 -119
  5. package/.agent/agents/database-architect.md +207 -164
  6. package/.agent/agents/debugger.md +218 -151
  7. package/.agent/agents/dependency-reviewer.md +136 -55
  8. package/.agent/agents/devops-engineer.md +238 -175
  9. package/.agent/agents/documentation-writer.md +221 -137
  10. package/.agent/agents/explorer-agent.md +180 -142
  11. package/.agent/agents/frontend-reviewer.md +194 -80
  12. package/.agent/agents/frontend-specialist.md +237 -188
  13. package/.agent/agents/game-developer.md +52 -184
  14. package/.agent/agents/logic-reviewer.md +149 -78
  15. package/.agent/agents/mobile-developer.md +223 -152
  16. package/.agent/agents/mobile-reviewer.md +195 -79
  17. package/.agent/agents/orchestrator.md +211 -170
  18. package/.agent/agents/penetration-tester.md +174 -131
  19. package/.agent/agents/performance-optimizer.md +203 -139
  20. package/.agent/agents/performance-reviewer.md +211 -108
  21. package/.agent/agents/product-manager.md +162 -108
  22. package/.agent/agents/project-planner.md +162 -142
  23. package/.agent/agents/qa-automation-engineer.md +242 -138
  24. package/.agent/agents/security-auditor.md +194 -170
  25. package/.agent/agents/seo-specialist.md +213 -132
  26. package/.agent/agents/sql-reviewer.md +194 -73
  27. package/.agent/agents/supervisor-agent.md +203 -156
  28. package/.agent/agents/test-coverage-reviewer.md +193 -81
  29. package/.agent/agents/type-safety-reviewer.md +208 -65
  30. package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
  31. package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
  32. package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
  33. package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
  34. package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
  35. package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
  36. package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
  37. package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
  38. package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
  39. package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
  40. package/.agent/skills/agent-organizer/SKILL.md +126 -132
  41. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +155 -66
  42. package/.agent/skills/api-patterns/SKILL.md +289 -257
  43. package/.agent/skills/api-security-auditor/SKILL.md +172 -70
  44. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
  45. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
  46. package/.agent/skills/appflow-wireframe/SKILL.md +107 -100
  47. package/.agent/skills/architecture/SKILL.md +331 -200
  48. package/.agent/skills/authentication-best-practices/SKILL.md +168 -67
  49. package/.agent/skills/bash-linux/SKILL.md +154 -215
  50. package/.agent/skills/brainstorming/SKILL.md +104 -210
  51. package/.agent/skills/building-native-ui/SKILL.md +169 -70
  52. package/.agent/skills/clean-code/SKILL.md +360 -206
  53. package/.agent/skills/config-validator/SKILL.md +141 -165
  54. package/.agent/skills/csharp-developer/SKILL.md +528 -107
  55. package/.agent/skills/database-design/SKILL.md +455 -275
  56. package/.agent/skills/deployment-procedures/SKILL.md +145 -188
  57. package/.agent/skills/devops-engineer/SKILL.md +332 -134
  58. package/.agent/skills/devops-incident-responder/SKILL.md +113 -98
  59. package/.agent/skills/edge-computing/SKILL.md +157 -213
  60. package/.agent/skills/extract-design-system/SKILL.md +129 -69
  61. package/.agent/skills/framer-motion-expert/SKILL.md +939 -0
  62. package/.agent/skills/game-design-expert/SKILL.md +105 -0
  63. package/.agent/skills/game-engineering-expert/SKILL.md +122 -0
  64. package/.agent/skills/geo-fundamentals/SKILL.md +124 -215
  65. package/.agent/skills/github-operations/SKILL.md +314 -354
  66. package/.agent/skills/gsap-expert/SKILL.md +901 -0
  67. package/.agent/skills/i18n-localization/SKILL.md +138 -216
  68. package/.agent/skills/intelligent-routing/SKILL.md +127 -139
  69. package/.agent/skills/llm-engineering/SKILL.md +357 -258
  70. package/.agent/skills/local-first/SKILL.md +154 -203
  71. package/.agent/skills/mcp-builder/SKILL.md +118 -224
  72. package/.agent/skills/nextjs-react-expert/SKILL.md +783 -203
  73. package/.agent/skills/nodejs-best-practices/SKILL.md +559 -280
  74. package/.agent/skills/observability/SKILL.md +330 -285
  75. package/.agent/skills/parallel-agents/SKILL.md +122 -181
  76. package/.agent/skills/performance-profiling/SKILL.md +254 -197
  77. package/.agent/skills/plan-writing/SKILL.md +118 -188
  78. package/.agent/skills/platform-engineer/SKILL.md +123 -135
  79. package/.agent/skills/playwright-best-practices/SKILL.md +157 -76
  80. package/.agent/skills/powershell-windows/SKILL.md +146 -230
  81. package/.agent/skills/python-pro/SKILL.md +879 -114
  82. package/.agent/skills/react-specialist/SKILL.md +931 -108
  83. package/.agent/skills/realtime-patterns/SKILL.md +304 -296
  84. package/.agent/skills/rust-pro/SKILL.md +701 -240
  85. package/.agent/skills/seo-fundamentals/SKILL.md +154 -181
  86. package/.agent/skills/server-management/SKILL.md +190 -212
  87. package/.agent/skills/shadcn-ui-expert/SKILL.md +201 -68
  88. package/.agent/skills/sql-pro/SKILL.md +633 -104
  89. package/.agent/skills/swiftui-expert/SKILL.md +171 -70
  90. package/.agent/skills/systematic-debugging/SKILL.md +118 -186
  91. package/.agent/skills/tailwind-patterns/SKILL.md +576 -232
  92. package/.agent/skills/tdd-workflow/SKILL.md +137 -209
  93. package/.agent/skills/testing-patterns/SKILL.md +573 -205
  94. package/.agent/skills/vue-expert/SKILL.md +964 -119
  95. package/.agent/skills/vulnerability-scanner/SKILL.md +269 -316
  96. package/.agent/skills/web-accessibility-auditor/SKILL.md +188 -71
  97. package/.agent/skills/webapp-testing/SKILL.md +145 -236
  98. package/.agent/workflows/api-tester.md +151 -279
  99. package/.agent/workflows/audit.md +138 -168
  100. package/.agent/workflows/brainstorm.md +110 -146
  101. package/.agent/workflows/changelog.md +112 -144
  102. package/.agent/workflows/create.md +124 -139
  103. package/.agent/workflows/debug.md +189 -196
  104. package/.agent/workflows/deploy.md +189 -153
  105. package/.agent/workflows/enhance.md +151 -139
  106. package/.agent/workflows/fix.md +135 -143
  107. package/.agent/workflows/generate.md +157 -164
  108. package/.agent/workflows/migrate.md +160 -163
  109. package/.agent/workflows/orchestrate.md +168 -151
  110. package/.agent/workflows/performance-benchmarker.md +123 -305
  111. package/.agent/workflows/plan.md +173 -151
  112. package/.agent/workflows/preview.md +80 -137
  113. package/.agent/workflows/refactor.md +183 -153
  114. package/.agent/workflows/review-ai.md +129 -140
  115. package/.agent/workflows/review.md +116 -155
  116. package/.agent/workflows/session.md +94 -154
  117. package/.agent/workflows/status.md +79 -125
  118. package/.agent/workflows/strengthen-skills.md +139 -99
  119. package/.agent/workflows/swarm.md +179 -194
  120. package/.agent/workflows/test.md +211 -166
  121. package/.agent/workflows/tribunal-backend.md +113 -111
  122. package/.agent/workflows/tribunal-database.md +115 -132
  123. package/.agent/workflows/tribunal-frontend.md +118 -115
  124. package/.agent/workflows/tribunal-full.md +133 -136
  125. package/.agent/workflows/tribunal-mobile.md +119 -123
  126. package/.agent/workflows/tribunal-performance.md +133 -152
  127. package/.agent/workflows/ui-ux-pro-max.md +143 -171
  128. package/README.md +11 -15
  129. package/package.json +1 -1
  130. package/.agent/skills/dotnet-core-expert/SKILL.md +0 -103
  131. package/.agent/skills/framer-motion-animations/SKILL.md +0 -74
  132. package/.agent/skills/game-development/2d-games/SKILL.md +0 -119
  133. package/.agent/skills/game-development/3d-games/SKILL.md +0 -135
  134. package/.agent/skills/game-development/SKILL.md +0 -236
  135. package/.agent/skills/game-development/game-art/SKILL.md +0 -185
  136. package/.agent/skills/game-development/game-audio/SKILL.md +0 -190
  137. package/.agent/skills/game-development/game-design/SKILL.md +0 -129
  138. package/.agent/skills/game-development/mobile-games/SKILL.md +0 -108
  139. package/.agent/skills/game-development/multiplayer/SKILL.md +0 -132
  140. package/.agent/skills/game-development/pc-games/SKILL.md +0 -144
  141. package/.agent/skills/game-development/vr-ar/SKILL.md +0 -123
  142. package/.agent/skills/game-development/web-games/SKILL.md +0 -150
@@ -1,203 +1,783 @@
1
- ---
2
- name: nextjs-react-expert
3
- description: Next.js App Router and React v19+ performance optimization from Vercel Engineering. Use when building React components, optimizing performance, implementing React Compiler patterns, eliminating waterfalls, reducing JS payload, or implementing Streaming/PPR optimizations.
4
- allowed-tools: Read, Write, Edit, Glob, Grep
5
- version: 1.0.0
6
- last-updated: 2026-03-12
7
- applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
8
- ---
9
-
10
- # React v19+ & Next.js Pro-Max Performance Patterns
11
-
12
- > The fastest code is code that doesn't run.
13
- > The second fastest is code that runs on the edge and streams the result.
14
-
15
- ---
16
-
17
- ## Contemporary Paradigm Shifts
18
-
19
- | Legacy (React 18 / Next.js Pages) | Modern (React 19 / Next.js App Router) |
20
- |---|---|
21
- | Manual `useMemo()` / `useCallback()` | **React Compiler** handles memoization natively |
22
- | `getServerSideProps` / Client Fetching | **React Server Components (RSC)** default |
23
- | `useActionState` custom hooks | **Server Actions** native mutations |
24
- | Loading spinners on client | **Streaming UI** & `Suspense` boundaries |
25
- | Static *or* Dynamic pages | **Partial Prerendering (PPR)** (Static shell, dynamic guts) |
26
-
27
- ---
28
-
29
- ## Core Architecture Decision Framework
30
-
31
- ### Server vs. Client Component
32
- By default, everything in Next.js App Router is a Server Component.
33
-
34
- ```
35
- Default: Server Component (Zero JS sent to client)
36
- Switch to Client ('use client') ONLY when:
37
- - Uses browser APIs (window, localStorage, navigator)
38
- - Needs DOM event handlers (onClick, onChange)
39
- - Needs state/effects (useState, useEffect, useOptimistic)
40
- ```
41
-
42
- **The Interleaved Pattern:** Never make a layout or major shell `'use client'`.
43
- Pass Server Components *into* Client components as `children`.
44
-
45
- ```tsx
46
- // Correct: The heavy static content stays on the server
47
- <ClientInteractiveDrawer>
48
- <ServerHeavyGraph data={dbData} />
49
- </ClientInteractiveDrawer>
50
- ```
51
-
52
- ---
53
-
54
- ## Extreme Waterfall Elimination
55
-
56
- The most impactful Next.js optimization is eliminating network waterfalls.
57
-
58
- ```tsx
59
- // ❌ CRITICAL WATERFALL: 3 sequential async calls, each waits for the previous
60
- async function Dashboard() {
61
- const user = await getUser(); // 200ms
62
- const posts = await getPosts(); // 200ms (waits unnecessarily)
63
- const analytics = await getAnalytics(); // 200ms (waits unnecessarily)
64
- // Total: 600ms (Blocked UI)
65
- }
66
- ```
67
-
68
- ### Fix 1: Parallel Fetching
69
- ```tsx
70
- // ✅ Parallel — all 3 start at the same time
71
- async function Dashboard() {
72
- const [user, posts, analytics] = await Promise.all([
73
- getUser(),
74
- getPosts(),
75
- getAnalytics(),
76
- ]);
77
- // Total: ~200ms (Blocked UI, but faster)
78
- }
79
- ```
80
-
81
- ### Fix 2: Streaming UI (The Pro-Max Way)
82
- Do not await slow data at the page level. Wrap slow components in `<Suspense>`.
83
-
84
- ```tsx
85
- // 🚀 PRO-MAX: Streaming Components
86
- export default function Dashboard() {
87
- return (
88
- <main>
89
- <FastHeader />
90
- <Suspense fallback={<AnalyticsSkeleton />}>
91
- {/* React streams this HTML down when the DB resolves */}
92
- <SlowAnalyticsComponent />
93
- </Suspense>
94
- </main>
95
- );
96
- }
97
- ```
98
-
99
- ---
100
-
101
- ## Partial Prerendering (PPR)
102
-
103
- PPR allows a single route to have both an ultra-fast static edge-cached shell, and dynamic personalized content streamed in instantly after execution.
104
-
105
- - Avoid using global `cookies()` or `headers()` high up in the component tree, as this forces the entire route to be dynamic.
106
- - Isolate dynamic data fetching within a `<Suspense>` boundary so the rest of the page can be statically pre-rendered at build time.
107
-
108
- ---
109
-
110
- ## AI & Streaming UI Responses
111
-
112
- When building GenAI interfaces, waiting for complete API responses breaks the "Doherty Threshold" (400ms).
113
-
114
- - **Use the `ai` SDK (`@ai-sdk/react`)** to stream text using `useChat` or `useCompletion`.
115
- - **Generative UI (RSC streaming):** Stream actual React Server Components back from the LLM, not just strings.
116
-
117
- ```tsx
118
- // ✅ AI Generative UI response
119
- return (
120
- <div>
121
- Here is the weather:
122
- <Suspense fallback={<WeatherSkeleton />}>
123
- <WeatherCard promise={llmTools.getWeather(location)} />
124
- </Suspense>
125
- </div>
126
- )
127
- ```
128
-
129
- ---
130
-
131
- ## Bundle Size & JS Dropping
132
-
133
- - **Import strictly:** Use barrel files cautiously. Ensure `package.json` `sideEffects: false` is respected so bundlers can tree-shake.
134
- - **Client boundaries low:** Push `'use client'` as far down the component tree as mathematically possible.
135
- - **Lazy loading heavy client deps:**
136
- ```tsx
137
- import dynamic from 'next/dynamic'
138
- // Only load D3.js when the user actually opens the modal
139
- const HeavyChart = dynamic(() => import('./HeavyChart'), { ssr: false })
140
- ```
141
-
142
- ---
143
-
144
- ## Key Anti-Patterns
145
-
146
- | Pattern | Problem | Fix |
147
- |---|---|---|
148
- | Fetching via `useEffect` | Client waterfall, huge CLS, breaks SSR | Fetch in RSC or use `SWR`/`React Query` |
149
- | Manual `useMemo` everywhere | Hurts code readability; React 18 legacy | Trust **React Compiler** to optimize renders automatically |
150
- | Missing `key` on mapped lists | Complete DOM destruction on update | Use stable unique IDs (never `index`) |
151
- | Unhandled Server Actions | Silent errors on DB failures | Wrap in `try/catch` and return `{ error }` objects |
152
- | Client-side secret passing | Exposes API keys | `server-only` package + Server Actions |
153
-
154
- ---
155
-
156
- ## Output Format
157
-
158
- When this skill produces or reviews code, structure your output as follows:
159
-
160
- ```
161
- ━━━ Nextjs React Expert Report ━━━━━━━━━━━━━━━━━━━━━━━━
162
- Skill: Nextjs React Expert
163
- Language: [detected language / framework]
164
- Scope: [N files · N functions]
165
- ─────────────────────────────────────────────────
166
- ✅ Passed: [checks that passed, or "All clean"]
167
- ⚠️ Warnings: [non-blocking issues, or "None"]
168
- ❌ Blocked: [blocking issues requiring fix, or "None"]
169
- ─────────────────────────────────────────────────
170
- VBC status: PENDING → VERIFIED
171
- Evidence: [test output / lint pass / compile success]
172
- ```
173
-
174
- **VBC (Verification-Before-Completion) is mandatory.**
175
- Do not mark status as VERIFIED until concrete terminal evidence is provided.
176
-
177
-
178
- ---
179
-
180
- ## 🏛️ Tribunal Integration (Anti-Hallucination)
181
-
182
- **Slash command: `/tribunal-frontend`**
183
- **Active reviewers: `logic` · `security` · `frontend` · `type-safety`**
184
-
185
- ### ❌ Forbidden AI Tropes in Next.js/React
186
-
187
- 1. **Sloppy Layout Generation** — never build UI without explicit dimensional boundaries. You MUST apply strict numeric design tokens (e.g. 4px grid spacing) and explicit flex/grid layouts.
188
- 2. **`"use client"` on everything** — do not convert Server Components to Client unless interaction/state is strictly required.
189
- 3. **`getServerSideProps` in App Router** — never hallucinate legacy Pages router data fetching in an App Router context.
190
- 4. **Unnecessary `useEffect` fetching** — always prefer Server Components or SWR/React Query for data fetching.
191
- 4. **Vercel clones** — do not default to generic black/white Vercel aesthetics unless instructed.
192
- 5. **Missing `key` in maps** — always provide a unique, stable key. No using iteration index as the key.
193
-
194
- ### ✅ Pre-Flight Self-Audit
195
-
196
- Review these questions before generating React/Next.js code:
197
- ```
198
- Did I maximize Server Component usage and isolate `'use client'` boundaries?
199
- Are there any sequential network calls creating a waterfall? If so, did I use `Promise.all` or `Suspense`?
200
- ✅ Did I ensure no sensitive environment variables leak to the client?
201
- ✅ Did I use `next/image` and `next/link` instead of raw `<img>` and `<a>` when appropriate?
202
- ✅ Did I implement proper loading/error boundaries (`loading.tsx`, `error.tsx`)?
203
- ```
1
+ ---
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.
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
8
+ ---
9
+
10
+ # Next.js 15+ App Router Pro-Max Patterns
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.
15
+
16
+ ---
17
+
18
+ ## Paradigm Shifts (Next.js 14 → 15+)
19
+
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
+ ```
34
+ 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
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Server vs Client Components
82
+
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
97
+
98
+ ```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
+
107
+ return (
108
+ <div className="flex">
109
+ <ClientSidebar> {/* client: has onClick, state */}
110
+ <ServerStats data={stats} /> {/* server: zero JS, renders HTML */}
111
+ </ClientSidebar>
112
+ </div>
113
+ );
114
+ }
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
+ ```
139
+
140
+ ---
141
+
142
+ ## Server Actions
143
+
144
+ ```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
+
177
+ import { revalidatePath } from "next/cache";
178
+ import { redirect } from "next/navigation";
179
+ import { z } from "zod";
180
+
181
+ const UserSchema = z.object({
182
+ name: z.string().min(2),
183
+ email: z.string().email(),
184
+ });
185
+
186
+ 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");
204
+ }
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
+ ```
213
+
214
+ ---
215
+
216
+ ## Data Fetching & Caching
217
+
218
+ ### Fetching in Server Components
219
+
220
+ ```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} />;
231
+ }
232
+ ```
233
+
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
+ ```
264
+
265
+ ### `unstable_cache` for Non-Fetch Data
266
+
267
+ ```tsx
268
+ import { unstable_cache } from "next/cache";
269
+
270
+ // Cache database queries that don't use fetch()
271
+ 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
+ }
280
+ );
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
+ ```
301
+
302
+ ### Fix 1: Parallel Fetching
303
+
304
+ ```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)
317
+
318
+ ```tsx
319
+ // 🚀 Show fast content immediately, stream slow content later
320
+ export default function Dashboard() {
321
+ return (
322
+ <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 */}
331
+ </Suspense>
332
+ </main>
333
+ );
334
+ }
335
+
336
+ // Each Suspense boundary independently streams its content
337
+ // The user sees the page progressively — not a blank screen
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Partial Prerendering (PPR)
343
+
344
+ ```tsx
345
+ // next.config.ts
346
+ export default {
347
+ experimental: {
348
+ ppr: true, // Enable Partial Prerendering
349
+ },
350
+ };
351
+
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
355
+
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} />
362
+
363
+ {/* 🔴 DYNAMIC — streamed on request (requires cookies/headers) */}
364
+ <Suspense fallback={<CartSkeleton />}>
365
+ <PersonalizedCart /> {/* reads cookies() — dynamic */}
366
+ </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);
491
+ }
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
+ ```
498
+
499
+ ---
500
+
501
+ ## Middleware
502
+
503
+ ```tsx
504
+ // middleware.ts (in project ROOT, not inside app/)
505
+ import { NextResponse } from "next/server";
506
+ import type { NextRequest } from "next/server";
507
+
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));
515
+ }
516
+
517
+ // Add custom headers
518
+ const response = NextResponse.next();
519
+ response.headers.set("x-pathname", pathname);
520
+
521
+ return response;
522
+ }
523
+
524
+ // Matcher: only run middleware on specific routes
525
+ 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
+ ],
532
+ };
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
+ ```
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.