opencastle 0.32.5 → 0.32.6

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 (69) hide show
  1. package/README.md +13 -3
  2. package/bin/cli.mjs +2 -0
  3. package/package.json +1 -1
  4. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  5. package/src/orchestrator/agents/api-designer.agent.md +25 -34
  6. package/src/orchestrator/agents/architect.agent.md +40 -84
  7. package/src/orchestrator/agents/content-engineer.agent.md +29 -31
  8. package/src/orchestrator/agents/copywriter.agent.md +35 -60
  9. package/src/orchestrator/agents/data-expert.agent.md +24 -30
  10. package/src/orchestrator/agents/database-engineer.agent.md +26 -31
  11. package/src/orchestrator/agents/developer.agent.md +32 -34
  12. package/src/orchestrator/agents/devops-expert.agent.md +31 -26
  13. package/src/orchestrator/agents/documentation-writer.agent.md +29 -29
  14. package/src/orchestrator/agents/performance-expert.agent.md +36 -33
  15. package/src/orchestrator/agents/release-manager.agent.md +25 -34
  16. package/src/orchestrator/agents/researcher.agent.md +41 -95
  17. package/src/orchestrator/agents/reviewer.agent.md +24 -34
  18. package/src/orchestrator/agents/security-expert.agent.md +35 -39
  19. package/src/orchestrator/agents/seo-specialist.agent.md +25 -32
  20. package/src/orchestrator/agents/session-guard.agent.md +20 -79
  21. package/src/orchestrator/agents/team-lead.agent.md +50 -254
  22. package/src/orchestrator/agents/testing-expert.agent.md +37 -49
  23. package/src/orchestrator/agents/ui-ux-expert.agent.md +33 -39
  24. package/src/orchestrator/customizations/KNOWN-ISSUES.md +0 -1
  25. package/src/orchestrator/customizations/agents/skill-matrix.json +12 -0
  26. package/src/orchestrator/instructions/general.instructions.md +24 -84
  27. package/src/orchestrator/plugins/astro/SKILL.md +23 -179
  28. package/src/orchestrator/plugins/convex/SKILL.md +38 -12
  29. package/src/orchestrator/plugins/netlify/SKILL.md +17 -13
  30. package/src/orchestrator/plugins/nextjs/SKILL.md +55 -261
  31. package/src/orchestrator/plugins/nx/SKILL.md +20 -72
  32. package/src/orchestrator/plugins/playwright/SKILL.md +5 -17
  33. package/src/orchestrator/plugins/slack/SKILL.md +28 -190
  34. package/src/orchestrator/plugins/teams/SKILL.md +10 -140
  35. package/src/orchestrator/plugins/vitest/SKILL.md +2 -2
  36. package/src/orchestrator/prompts/bug-fix.prompt.md +25 -63
  37. package/src/orchestrator/prompts/implement-feature.prompt.md +29 -66
  38. package/src/orchestrator/prompts/quick-refinement.prompt.md +31 -66
  39. package/src/orchestrator/skills/accessibility-standards/SKILL.md +50 -105
  40. package/src/orchestrator/skills/agent-hooks/SKILL.md +60 -110
  41. package/src/orchestrator/skills/agent-memory/SKILL.md +44 -93
  42. package/src/orchestrator/skills/api-patterns/SKILL.md +20 -68
  43. package/src/orchestrator/skills/code-commenting/SKILL.md +49 -101
  44. package/src/orchestrator/skills/context-map/SKILL.md +47 -88
  45. package/src/orchestrator/skills/data-engineering/SKILL.md +27 -74
  46. package/src/orchestrator/skills/decomposition/SKILL.md +50 -98
  47. package/src/orchestrator/skills/deployment-infrastructure/SKILL.md +44 -107
  48. package/src/orchestrator/skills/documentation-standards/SKILL.md +28 -89
  49. package/src/orchestrator/skills/fast-review/SKILL.md +51 -276
  50. package/src/orchestrator/skills/frontend-design/SKILL.md +53 -163
  51. package/src/orchestrator/skills/git-workflow/SKILL.md +18 -54
  52. package/src/orchestrator/skills/memory-merger/SKILL.md +51 -88
  53. package/src/orchestrator/skills/observability-logging/SKILL.md +29 -75
  54. package/src/orchestrator/skills/orchestration-protocols/SKILL.md +58 -117
  55. package/src/orchestrator/skills/panel-majority-vote/SKILL.md +65 -140
  56. package/src/orchestrator/skills/performance-optimization/SKILL.md +21 -85
  57. package/src/orchestrator/skills/project-consistency/SKILL.md +62 -281
  58. package/src/orchestrator/skills/react-development/SKILL.md +38 -86
  59. package/src/orchestrator/skills/security-hardening/SKILL.md +40 -84
  60. package/src/orchestrator/skills/self-improvement/SKILL.md +26 -60
  61. package/src/orchestrator/skills/seo-patterns/SKILL.md +40 -105
  62. package/src/orchestrator/skills/session-checkpoints/SKILL.md +26 -68
  63. package/src/orchestrator/skills/team-lead-reference/SKILL.md +66 -206
  64. package/src/orchestrator/skills/testing-workflow/SKILL.md +42 -112
  65. package/src/orchestrator/skills/validation-gates/SKILL.md +39 -170
  66. package/src/orchestrator/snippets/base-output-contract.md +14 -0
  67. package/src/orchestrator/snippets/discovered-issues-policy.md +15 -0
  68. package/src/orchestrator/snippets/logging-mandatory.md +11 -0
  69. package/src/orchestrator/snippets/never-expose-secrets.md +22 -0
@@ -16,149 +16,93 @@ description: "Next.js framework best practices covering App Router, server/clien
16
16
  │ ├── loading.tsx # Loading UI (Suspense boundary)
17
17
  │ ├── error.tsx # Error boundary (Client Component)
18
18
  │ ├── not-found.tsx # 404 page
19
- │ ├── global-error.tsx # Root error boundary
20
19
  │ ├── (marketing)/ # Route group (no URL segment)
21
- │ │ ├── about/page.tsx # → /about
22
- │ │ └── blog/page.tsx # → /blog
20
+ │ │ └── about/page.tsx # → /about
23
21
  │ ├── dashboard/
24
22
  │ │ ├── layout.tsx # Nested layout
25
- │ │ ├── page.tsx # → /dashboard
26
23
  │ │ └── [id]/page.tsx # → /dashboard/:id
27
24
  │ └── api/
28
25
  │ └── users/route.ts # API route handler
29
26
  ├── components/ # Shared React components
30
27
  ├── lib/ # Utilities, helpers, server logic
31
- ├── public/ # Static assets (served as-is)
28
+ ├── public/ # Static assets
32
29
  ├── next.config.ts # Next.js configuration
33
30
  ├── middleware.ts # Edge middleware
34
31
  └── .env.local # Environment variables (not committed)
35
32
  ```
36
33
 
37
- - **Route Groups** `(name)` organize routes without affecting the URL.
38
- - **Private Folders** `_internal` — opt out of routing entirely.
39
- - **Parallel Routes** `@modal` — render multiple pages in the same layout.
40
- - **Intercepting Routes** `(.)photo` — intercept navigation to show modals.
34
+ Route Groups `(name)` organize routes without affecting the URL. Private Folders `_internal` opt out of routing. Parallel Routes `@modal` render multiple pages in the same layout.
41
35
 
42
36
  ## Rendering Strategies
43
37
 
44
- Next.js supports multiple rendering strategies per route:
45
-
46
38
  | Strategy | When | How |
47
39
  |----------|------|-----|
48
40
  | **Static (SSG)** | Build time | Default for pages with no dynamic data |
49
- | **Incremental Static Regeneration (ISR)** | Build + revalidation | `fetch` with `next: { revalidate: N }` or route segment config |
50
- | **Server-Side Rendering (SSR)** | Every request | `export const dynamic = 'force-dynamic'` or dynamic functions (`cookies()`, `headers()`) |
51
- | **Client-Side Rendering (CSR)** | Browser | `'use client'` components with `useEffect`/SWR |
41
+ | **ISR** | Build + revalidation | `fetch` with `next: { revalidate: N }` or route segment config |
42
+ | **SSR** | Every request | `export const dynamic = 'force-dynamic'` or dynamic functions |
43
+ | **CSR** | Browser | `'use client'` components with `useEffect`/SWR |
52
44
  | **Streaming** | Progressive | `<Suspense>` boundaries + `loading.tsx` |
53
- | **Partial Prerendering (PPR)** | Build + streaming | Static shell with dynamic holes via `<Suspense>` |
54
-
55
- ### Route Segment Config
56
-
57
- Control per-route rendering behavior:
45
+ | **PPR** | Build + streaming | Static shell with dynamic holes via `<Suspense>` |
58
46
 
59
- ```tsx
60
- // app/dashboard/page.tsx
61
- export const dynamic = 'force-dynamic'; // SSR every request
62
- export const revalidate = 60; // ISR: revalidate every 60s
63
- export const fetchCache = 'default-cache'; // Cache fetch requests
64
- export const runtime = 'nodejs'; // 'nodejs' | 'edge'
65
- ```
47
+ Route segment config: `export const dynamic = 'force-dynamic'`, `export const revalidate = 60`, `export const runtime = 'edge'`.
66
48
 
67
49
  ## Server and Client Components
68
50
 
69
- **Default: Server Components** — data fetching, heavy logic, non-interactive UI.
70
-
51
+ **Default: Server Components** — data fetching, heavy logic, non-interactive UI.
71
52
  **Client Components** — add `'use client'` at top. Use for interactivity, state, browser APIs.
72
53
 
73
- ### Decision Table
74
-
75
- | Need | Component Type | Why |
76
- |------|---------------|-----|
77
- | Fetch data at request time | Server | Direct DB/API access, no client waterfall |
78
- | Read cookies/headers | Server | Available only on the server |
79
- | Interactive UI (clicks, inputs) | Client | Requires event handlers |
80
- | Use `useState` / `useEffect` | Client | React hooks need client runtime |
81
- | Access browser APIs (localStorage, geolocation) | Client | Not available on server |
82
- | Render static/non-interactive content | Server | Smaller bundle, faster paint |
83
- | Show loading spinners for async children | Server (with `<Suspense>`) | Streams HTML progressively |
54
+ | Need | Component Type |
55
+ |------|---------------|
56
+ | Fetch data / read cookies/headers | Server |
57
+ | Interactive UI (clicks, inputs) | Client |
58
+ | `useState` / `useEffect` / browser APIs | Client |
59
+ | Static/non-interactive content | Server |
60
+ | Async children with loading state | Server + `<Suspense>` |
84
61
 
85
62
  ### Critical Rule
86
63
 
87
- **Never use `next/dynamic` with `{ ssr: false }` inside a Server Component.** Move client-only logic into a dedicated `'use client'` component, then import it normally.
64
+ **Never use `next/dynamic` with `{ ssr: false }` inside a Server Component.** Extract to a dedicated `'use client'` component and import it normally.
88
65
 
89
66
  ## Data Fetching
90
67
 
91
- ### Server-Side Fetching
92
-
93
- Fetch directly in `async` Server Components. Next.js deduplicates identical `fetch` calls.
68
+ ### Server-Side
94
69
 
95
70
  ```tsx
96
71
  export default async function ProjectsPage() {
97
- const projects = await fetch('https://api.example.com/projects', {
98
- next: { revalidate: 60 },
99
- }).then((res) => res.json());
100
- return <ul>{projects.map((p: { id: string; name: string }) => <li key={p.id}>{p.name}</li>)}</ul>;
72
+ const data = await fetch('/api/projects', { next: { revalidate: 60 } }).then((r) => r.json());
73
+ return <ul>{data.map((p: { id: string; name: string }) => <li key={p.id}>{p.name}</li>)}</ul>;
101
74
  }
102
75
  ```
103
76
 
104
- ### Server Actions (Mutations)
105
-
106
- Define with `'use server'`. Call from Client Components via `action` or `startTransition`.
77
+ ### Server Actions
107
78
 
108
79
  ```tsx
109
- // lib/actions.ts
110
80
  'use server';
111
81
  import { revalidatePath } from 'next/cache';
112
82
  export async function createItem(formData: FormData) {
113
- const name = formData.get('name') as string;
114
- await db.items.create({ data: { name } });
83
+ await db.items.create({ data: { name: formData.get('name') as string } });
115
84
  revalidatePath('/items');
116
85
  }
117
86
  ```
118
87
 
119
- ```tsx
120
- // components/CreateItemForm.tsx
121
- 'use client';
122
- import { createItem } from '@/lib/actions';
123
- export default function CreateItemForm() {
124
- return <form action={createItem}><input name="name" required /><button type="submit">Add</button></form>;
125
- }
126
- ```
88
+ Use from a Client Component: `<form action={createItem}>...</form>`
127
89
 
128
- ### Parallel Data Fetching
129
-
130
- Initiate independent fetches simultaneously — never `await` sequentially.
90
+ ### Parallel Fetching
131
91
 
132
92
  ```tsx
133
- export default async function DashboardPage() {
134
- const [metrics, activity] = await Promise.all([getMetrics(), getRecentActivity()]);
135
- return <><MetricsPanel data={metrics} /><ActivityFeed items={activity} /></>;
136
- }
93
+ const [metrics, activity] = await Promise.all([getMetrics(), getRecentActivity()]);
137
94
  ```
138
95
 
139
- ## Caching and Revalidation
96
+ ## Caching
140
97
 
141
98
  | Mechanism | Scope | How to Use |
142
99
  |-----------|-------|------------|
143
100
  | **Request Memoization** | Per-request | Automatic deduplication of identical `fetch` calls |
144
- | **Data Cache** | Cross-request | `fetch` results cached by default; opt out with `cache: 'no-store'` |
101
+ | **Data Cache** | Cross-request | Cached by default; opt out with `cache: 'no-store'` |
145
102
  | **Full Route Cache** | Build time | Static routes cached as HTML + RSC payload |
146
103
  | **Router Cache** | Client-side | Prefetched and visited routes cached in browser |
147
104
 
148
- ### Revalidation
149
-
150
- ```tsx
151
- // Time-based — revalidate every 60 seconds
152
- fetch(url, { next: { revalidate: 60 } });
153
-
154
- // On-demand — revalidate by path or tag
155
- import { revalidatePath, revalidateTag } from 'next/cache';
156
- revalidatePath('/blog');
157
- revalidateTag('posts');
158
-
159
- // Tag a fetch for on-demand revalidation
160
- fetch(url, { next: { tags: ['posts'] } });
161
- ```
105
+ On-demand revalidation: `revalidatePath('/blog')` or `revalidateTag('posts')`. Tag a fetch: `fetch(url, { next: { tags: ['posts'] } })`.
162
106
 
163
107
  ## Routing
164
108
 
@@ -166,211 +110,61 @@ fetch(url, { next: { tags: ['posts'] } });
166
110
 
167
111
  | File | Purpose |
168
112
  |------|---------|
169
- | `page.tsx` | Route UI (makes segment publicly accessible) |
170
- | `layout.tsx` | Shared layout (wraps children, persists across navigation) |
113
+ | `page.tsx` | Route UI |
114
+ | `layout.tsx` | Shared layout (persists across navigation) |
171
115
  | `template.tsx` | Like layout but re-mounts on navigation |
172
116
  | `loading.tsx` | Loading UI (automatic Suspense boundary) |
173
- | `error.tsx` | Error UI (Client Component, automatic error boundary) |
117
+ | `error.tsx` | Error UI (Client Component) |
174
118
  | `not-found.tsx` | 404 UI |
175
- | `route.ts` | API endpoint (no UI) |
119
+ | `route.ts` | API endpoint |
176
120
  | `default.tsx` | Fallback for parallel routes |
177
121
 
178
122
  ### Dynamic Routes
179
123
 
180
- ```
181
- app/blog/[slug]/page.tsx /blog/:slug
182
- app/shop/[...slug]/page.tsx /shop/:slug+ (catch-all)
183
- app/shop/[[...slug]]/page.tsx → /shop or /shop/:slug+ (optional catch-all)
184
- ```
185
-
186
- ### Route Handlers (API Routes)
187
-
188
- ```ts
189
- // app/api/users/route.ts
190
- import { NextRequest, NextResponse } from 'next/server';
191
-
192
- export async function GET(request: NextRequest) {
193
- const { searchParams } = request.nextUrl;
194
- const query = searchParams.get('q');
195
- const users = await findUsers(query);
196
- return NextResponse.json(users);
197
- }
198
-
199
- export async function POST(request: NextRequest) {
200
- const body = await request.json();
201
- const user = await createUser(body);
202
- return NextResponse.json(user, { status: 201 });
203
- }
204
- ```
205
-
206
- ## Error Handling
207
-
208
- ```tsx
209
- // app/dashboard/error.tsx — must be a Client Component
210
- 'use client';
211
- export default function DashboardError({ error, reset }: { error: Error; reset: () => void }) {
212
- return <div role="alert"><h2>Something went wrong</h2><button onClick={reset}>Try again</button></div>;
213
- }
214
- ```
215
-
216
- ```tsx
217
- // app/projects/[id]/page.tsx — trigger not-found boundary
218
- import { notFound } from 'next/navigation';
219
- export default async function ProjectPage({ params }: { params: { id: string } }) {
220
- const project = await getProject(params.id);
221
- if (!project) notFound();
222
- return <h1>{project.name}</h1>;
223
- }
224
- ```
124
+ - `app/blog/[slug]/page.tsx` → `/blog/:slug`
125
+ - `app/shop/[...slug]/page.tsx` `/shop/:slug+` (catch-all)
126
+ - `app/shop/[[...slug]]/page.tsx` `/shop` or `/shop/:slug+` (optional)
225
127
 
226
128
  ## Middleware
227
129
 
228
- Runs at the Edge before every matched request. Use for auth, redirects, rewrites, headers.
130
+ Runs at the Edge before every matched request. Use for auth, redirects, rewrites.
229
131
 
230
132
  ```ts
231
133
  import { NextResponse, type NextRequest } from 'next/server';
232
-
233
- export function middleware(request: NextRequest) {
234
- const token = request.cookies.get('session')?.value;
235
- if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
236
- return NextResponse.redirect(new URL('/login', request.url));
237
- }
238
- // Add custom headers
239
- const response = NextResponse.next();
240
- response.headers.set('x-request-id', crypto.randomUUID());
241
- return response;
134
+ export function middleware(req: NextRequest) {
135
+ if (!req.cookies.get('session') && req.nextUrl.pathname.startsWith('/dashboard'))
136
+ return NextResponse.redirect(new URL('/login', req.url));
137
+ return NextResponse.next();
242
138
  }
243
-
244
- export const config = { matcher: ['/dashboard/:path*', '/settings/:path*'] };
139
+ export const config = { matcher: ['/dashboard/:path*'] };
245
140
  ```
246
141
 
247
- ## Configuration
248
-
249
- ### `next.config.ts`
250
-
251
- ```ts
252
- import type { NextConfig } from 'next';
253
-
254
- const nextConfig: NextConfig = {
255
- reactStrictMode: true,
256
- images: {
257
- remotePatterns: [
258
- { protocol: 'https', hostname: 'cdn.example.com' },
259
- ],
260
- },
261
- experimental: {
262
- ppr: true, // Partial Prerendering
263
- typedRoutes: true, // Type-safe <Link> hrefs
264
- },
265
- // Redirects, rewrites, headers
266
- async redirects() {
267
- return [{ source: '/old-path', destination: '/new-path', permanent: true }];
268
- },
269
- };
270
-
271
- export default nextConfig;
272
- ```
273
-
274
- ### Environment Variables
142
+ ## Environment Variables
275
143
 
276
144
  | Prefix | Available in | Use Case |
277
145
  |--------|-------------|----------|
278
146
  | `NEXT_PUBLIC_` | Server + Client | Public values (API base URLs, feature flags) |
279
147
  | No prefix | Server only | Secrets (DB URLs, API keys, tokens) |
280
148
 
281
- Files loaded (in priority order): `.env.local`, `.env.development` / `.env.production`, `.env`.
282
-
283
- ## Image and Font Optimization
284
-
285
- ### Images
286
-
287
- ```tsx
288
- import Image from 'next/image';
289
- import heroImg from '@/public/hero.jpg';
290
-
291
- // Local image — auto width/height from import
292
- <Image src={heroImg} alt="Hero" priority />
293
-
294
- // Remote image — must specify dimensions
295
- <Image src="https://cdn.example.com/photo.jpg" alt="Photo" width={800} height={600} />
296
- ```
297
-
298
- ### Fonts
299
-
300
- ```tsx
301
- // app/layout.tsx
302
- import { Inter } from 'next/font/google';
303
- const inter = Inter({ subsets: ['latin'], display: 'swap' });
304
-
305
- export default function RootLayout({ children }: { children: React.ReactNode }) {
306
- return <html lang="en" className={inter.className}><body>{children}</body></html>;
307
- }
308
- ```
309
-
310
- ## Metadata and SEO
311
-
312
- ```tsx
313
- // app/layout.tsx — static metadata
314
- import type { Metadata } from 'next';
315
-
316
- export const metadata: Metadata = {
317
- title: { default: 'My App', template: '%s | My App' },
318
- description: 'App description',
319
- openGraph: { title: 'My App', description: 'App description', type: 'website' },
320
- };
321
- ```
322
-
323
- ```tsx
324
- // app/blog/[slug]/page.tsx — dynamic metadata
325
- import type { Metadata } from 'next';
326
-
327
- export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
328
- const post = await getPost(params.slug);
329
- return { title: post.title, description: post.excerpt };
330
- }
331
- ```
332
-
333
- ## Performance Patterns
334
-
335
- - **Default to Server Components** — smaller client bundles, faster paint.
336
- - **`<Suspense>` + `loading.tsx`** — stream content progressively; never block the whole page.
337
- - **`Promise.all()`** — parallel data fetching for independent data.
338
- - **Dynamic imports** — lazy-load heavy Client Components with `next/dynamic`.
339
- - **`<Image>`** — automatic lazy loading, responsive sizing, format conversion.
340
- - **`next/font`** — zero layout shift, self-hosted fonts.
341
- - **Route segment config** — fine-tune caching and rendering per route.
342
-
343
- ## Deployment
344
-
345
- Next.js deploys to multiple targets:
346
-
347
- | Target | Config | Notes |
348
- |--------|--------|-------|
349
- | **Vercel** | Zero-config | Full feature support including Edge, ISR, Middleware |
350
- | **Node.js server** | `output: 'standalone'` | Minimal `standalone/` folder with server |
351
- | **Docker** | `output: 'standalone'` | Copy `.next/standalone` + `.next/static` + `public` |
352
- | **Static export** | `output: 'export'` | No server features (no SSR, API routes, middleware) |
149
+ Files (priority order): `.env.local`, `.env.development` / `.env.production`, `.env`.
353
150
 
354
- ## Component Practices & Naming
151
+ ## Image, Font, and Metadata
355
152
 
356
- - PascalCase for component files/exports. camelCase for hooks.
357
- - Shared components in `components/`. Route-specific components co-located in route folder.
358
- - TypeScript interfaces for props. Explicit types and defaults.
359
- - Co-locate tests with components.
360
- - Folders: `kebab-case`. Types/Interfaces: `PascalCase`. Constants: `UPPER_SNAKE_CASE`.
153
+ - **Images**: Use `<Image>` from `next/image` — auto lazy loading, responsive sizing, format conversion. Configure `images.remotePatterns` in `next.config.ts` for remote URLs.
154
+ - **Fonts**: Use `next/font/google` zero layout shift, self-hosted, no external network request.
155
+ - **Metadata**: Export `metadata` (static) or `generateMetadata` (dynamic) per page/layout for SEO and social previews.
361
156
 
362
157
  ## Anti-Patterns
363
158
 
364
159
  | Anti-Pattern | Why It's Wrong | Do This Instead |
365
160
  |-------------|---------------|-----------------|
366
- | `'use client'` on every component | Bloats JS bundle, defeats RSC benefits | Default to Server Components; add `'use client'` only when needed |
367
- | Sequential `await` for independent data | Creates a waterfall, slows page load | Use `Promise.all()` for parallel fetches |
368
- | `next/dynamic` with `ssr: false` in Server Components | Build/runtime crash | Extract to a Client Component, import normally |
369
- | Fetching in `useEffect` when server fetch works | Extra client roundtrip, loading flash | Fetch in the Server Component or use Server Actions |
370
- | Giant `layout.tsx` with all providers | Hard to test, couples unrelated concerns | Split providers into a `Providers` Client Component |
371
- | Catching errors without `error.tsx` | Unhandled errors crash the page | Add `error.tsx` per route segment |
372
- | Hardcoding secrets in source files | Security risk, leaks in version control | Use `.env.local` and `process.env` |
161
+ | `'use client'` on every component | Bloats JS bundle, defeats RSC benefits | Default to Server Components |
162
+ | Sequential `await` for independent data | Waterfall, slows page load | Use `Promise.all()` |
163
+ | `next/dynamic` with `ssr: false` in Server Components | Build/runtime crash | Extract to Client Component |
164
+ | Fetching in `useEffect` when server fetch works | Extra roundtrip, loading flash | Fetch in Server Component or Server Actions |
165
+ | Giant `layout.tsx` with all providers | Hard to test, couples concerns | Split into a `Providers` Client Component |
166
+ | No `error.tsx` per segment | Unhandled errors crash the page | Add `error.tsx` per route segment |
167
+ | Hardcoding secrets in source | Security risk, version control leak | Use `.env.local` and `process.env` |
373
168
  | Skipping `loading.tsx` / `<Suspense>` | Blank screen while data loads | Add `loading.tsx` or wrap in `<Suspense>` |
374
- | Using `getServerSideProps` / `getStaticProps` | Legacy Pages Router patterns | Use App Router with `async` Server Components |
375
- | Ignoring `next.config.ts` for images | Remote images blocked by default | Configure `images.remotePatterns` |
169
+ | `getServerSideProps` / `getStaticProps` | Legacy Pages Router | Use App Router with async Server Components |
376
170
  | Missing `metadata` exports | Poor SEO, no social previews | Export `metadata` or `generateMetadata` per page |
@@ -96,98 +96,46 @@ The NX MCP server provides tools for understanding and working with the workspac
96
96
 
97
97
  ## Code Generation Workflow
98
98
 
99
- Use this workflow whenever scaffolding new code (libraries, applications, features) or running automated code transformations. **Always prefer generators over manual file creation** when a generator exists for the task.
99
+ Always prefer generators over manual file creation when a generator exists.
100
100
 
101
101
  ### Phase 1: Discover
102
102
 
103
- 1. **List available generators** using `nx_generators` MCP tool
104
- - This includes plugin generators (e.g., `@nx/react:library`) and local workspace generators
105
- 2. **Match generator to request** identify which generator(s) could fulfill the need
106
- 3. **Prefer local generators** — when both local and plugin generators could work, **always prefer local** (they're customized for this repo's patterns)
107
- 4. **If no generator fits** — check `nx_available_plugins` for installable plugins. Only fall back to manual creation after exhausting all generator options
103
+ 1. List available generators using `nx_generators` MCP tool (plugin + local workspace generators)
104
+ 2. Prefer local generators over plugin generators they're customized for this repo
105
+ 3. If no generator fits, check `nx_available_plugins`; only fall back to manual creation after exhausting all generator options
108
106
 
109
107
  ### Phase 2: Understand
110
108
 
111
- Before running any generator, complete these steps:
112
-
113
- 1. **Fetch generator schema** using `nx_generator_schema` MCP tool
114
- - Identify required vs optional options
115
- - Note default values that may need overriding
116
- - Pay attention to options that affect file structure or naming
117
-
118
- 2. **Read generator source code** (for unfamiliar generators)
119
- - Find source: `node -e "console.log(require.resolve('@nx/<plugin>/generators.json'));"`
120
- - If that fails: read from `node_modules/<plugin>/generators.json`
121
- - Local generators: check `tools/generators/` or local plugin directories
122
- - Understanding the source reveals side effects (config updates, dep installs) and files created/modified
123
-
124
- 3. **Reevaluate generator choice** — after understanding what the generator does, confirm it's the right one. If not, go back to Phase 1 and select a different generator.
125
-
126
- 4. **Examine repo context** — study existing similar artifacts in the codebase:
127
- - Look at how similar projects are structured (naming, test runner, build tool, linter)
128
- - Match conventions when configuring the generator
129
- - Note directory structures, file patterns, and config styles
130
-
131
- 5. **Validate required options** — map the user's request to generator options:
132
- - Infer values from context where possible
133
- - Ask for critical missing information if it cannot be inferred
109
+ 1. Fetch generator schema using `nx_generator_schema` — note required options, defaults, and file structure impacts
110
+ 2. Read generator source to understand side effects (config updates, dep installs, files created/modified)
111
+ 3. Examine existing similar artifacts for naming, structure, test runner, and config conventions; map user's request to generator options
134
112
 
135
113
  ### Phase 3: Execute
136
114
 
137
- 1. **Consider dry-run first** (recommended for complex/unfamiliar generators):
138
- ```bash
139
- yarn nx generate <generator-name> <options> --dry-run --no-interactive
140
- ```
141
- - Shows files that would be created/deleted/modified (but not content)
142
- - Some generators don't support dry-run (e.g., if they install packages) — skip and run for real
143
- - For simple, well-understood generators, you may skip dry-run
115
+ ```bash
116
+ yarn nx generate <generator-name> <options> --dry-run --no-interactive # optional preview
117
+ yarn nx generate <generator-name> <options> --no-interactive
118
+ ```
144
119
 
145
- 2. **Run the generator**:
146
- ```bash
147
- yarn nx generate <generator-name> <options> --no-interactive
148
- ```
149
- **CRITICAL**: Always include `--no-interactive` to prevent prompts that hang execution.
120
+ **CRITICAL**: Always include `--no-interactive` to prevent prompts that hang execution.
150
121
 
151
- **CRITICAL**: Generators may behave differently based on the current working directory (e.g., library generators use cwd to determine placement). Verify cwd before running.
122
+ **CRITICAL**: Verify cwd before running generators may use it to determine file placement.
152
123
 
153
- 3. **Handle failures** if the generator fails:
154
- - Read the error message carefully
155
- - Common causes: missing required options, invalid values, conflicting files, missing dependencies
156
- - Adjust options and retry
157
- - Use the **self-improvement** skill to add a lesson if the fix was non-obvious
124
+ On failure: read the error, adjust options, and retry. Use the **self-improvement** skill for non-obvious fixes.
158
125
 
159
126
  ### Phase 4: Post-Generation
160
127
 
161
- 1. **Modify generated code** if needed generators provide a starting point:
162
- - Adjust functionality to match specific requirements
163
- - Update imports, exports, configurations
164
- - Integrate with existing code patterns
165
-
166
- 2. **Format code**:
167
- ```bash
168
- yarn nx format --fix
169
- ```
170
-
171
- 3. **Run verification** on generated/affected projects:
172
- ```bash
173
- yarn nx run <new-project>:lint --fix
174
- yarn nx run <new-project>:test
175
- yarn nx run <new-project>:build
176
- ```
177
-
178
- 4. **Handle verification failures**:
179
- - **Small scope** (few lint errors, minor type issues) — fix directly, re-verify
180
- - **Large scope** (many errors, complex problems) — fix obvious issues first, escalate remaining with description of what was generated, what's failing, and what was attempted
128
+ 1. Modify generated code to match requirements (imports, exports, config, integrations)
129
+ 2. Format: `yarn nx format --fix`
130
+ 3. Verify lint, test, and build on generated/affected projects; fix small-scope issues directly, escalate large-scope failures
181
131
 
182
132
  ## Running Tasks Workflow
183
133
 
184
- When helping with build, test, lint, or serve tasks:
185
-
186
134
  1. Use `nx_current_running_tasks_details` to check for active/completed/failed tasks
187
- 2. For a specific task, use `nx_current_running_task_output` to get its terminal output
135
+ 2. Use `nx_current_running_task_output` to get terminal output for a specific task
188
136
  3. Diagnose issues from the output and apply fixes
189
- 4. To rerun a task, always use `yarn nx run <taskId>` to preserve the NX context
190
- 5. **Continuous tasks** (like `serve`) are already running — don't offer to rerun, just check output
137
+ 4. To rerun, use `yarn nx run <taskId>` to preserve NX context
138
+ 5. **Continuous tasks** (like `serve`) are already running — don't rerun, just check output
191
139
 
192
140
  ## Project Names
193
141
 
@@ -103,25 +103,12 @@ export class LoginPage {
103
103
  }
104
104
  ```
105
105
 
106
- ### Custom Fixtures
106
+ ## API Mocking
107
107
 
108
108
  ```typescript
109
- // tests/fixtures/auth.fixture.ts
110
- import { test as base } from '@playwright/test';
111
-
112
- type AuthFixtures = {
113
- authenticatedPage: Page;
114
- };
115
-
116
- export const test = base.extend<AuthFixtures>({
117
- authenticatedPage: async ({ page }, use) => {
118
- await page.goto('/login');
119
- await page.getByTestId('email-input').fill('test@example.com');
120
- await page.getByTestId('password-input').fill('password');
121
- await page.getByTestId('login-button').click();
122
- await page.waitForURL('**/dashboard');
123
- await use(page);
124
- },
109
+ // Mock API responses for deterministic tests
110
+ await page.route('/api/login', (route) => {
111
+ route.fulfill({ status: 200, body: JSON.stringify({ token: 'test' }) });
125
112
  });
126
113
  ```
127
114
 
@@ -189,3 +176,4 @@ The Playwright MCP server enables AI agents to interact with browsers directly:
189
176
  - Run tests in parallel (`fullyParallel: true`) for speed
190
177
  - Use `trace: 'on-first-retry'` to debug flaky tests
191
178
  - Use `codegen` to bootstrap tests, then refactor into page objects
179
+ - Use `page.route()` to mock API responses — create isolated, deterministic tests without backend dependencies