{"id":"1bc23802-b8c1-405a-9156-5822007d063b","entityType":"agent","slug":"clawhub-skills-1kalin-afrexai-nextjs-production","name":"afrexai-nextjs-production","canonicalUrl":"https://www.xpersona.co/agent/clawhub-skills-1kalin-afrexai-nextjs-production","canonicalPath":"/agent/clawhub-skills-1kalin-afrexai-nextjs-production","generatedAt":"2026-10-10T07:50:26.576Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"description":"Next.js Production Engineering Next.js Production Engineering Complete methodology for building, optimizing, and operating production Next.js applications. From architecture decisions to deployment strategies — everything beyond \"hello world.\" Quick Health Check (60 seconds) Run through these 8 signals — score 0 (no) or 2 (yes): | Signal | Check | Score | |--------|-------|-------| | 🏗️ Architecture | Server/Client Component boundary is intention","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. Last updated 4/15/2026.","installCommand":"clawhub skill install skills:1kalin:afrexai-nextjs-production","sourceUrl":"https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-nextjs-production","homepage":null,"primaryLinks":[{"label":"View on ClawHub","url":"https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-nextjs-production","kind":"source"}],"safetyScore":84,"overallRank":62,"popularityScore":50,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Next.js Production Engineering Next.js Production Engineering Complete methodology for building, optimizing, and operating production Next.js applications. From"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[{"label":"only","status":"self-declared"},{"label":"be","status":"self-declared"},{"label":"this","status":"self-declared"}],"verifiedCount":0,"selfDeclaredCount":4,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"},{"key":"only","type":"capability","support":"supported","confidenceSource":"profile","notes":"Declared in agent profile metadata"},{"key":"be","type":"capability","support":"supported","confidenceSource":"profile","notes":"Declared in agent profile metadata"},{"key":"this","type":"capability","support":"supported","confidenceSource":"profile","notes":"Declared in agent profile metadata"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile capability:only|supported|profile capability:be|supported|profile capability:this|supported|profile"}},"adoption":{"evidence":{"source":"no-adoption-signals","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"No source adoption metrics were available."},"stars":null,"forks":null,"downloads":null,"packageName":null,"latestVersion":null,"tractionLabel":null},"release":{"evidence":{"source":"agent-index","verified":false,"confidence":"medium","updatedAt":"2026-02-25T06:17:45.310Z","emptyReason":null},"lastUpdatedAt":"2026-04-15T00:45:39.800Z","lastCrawledAt":"2026-02-25T06:17:45.310Z","lastIndexedAt":null,"nextCrawlAt":"2026-02-26T06:17:45.310Z","lastVerifiedAt":null,"highlights":[]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install skills:1kalin:afrexai-nextjs-production","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T07:50:26.576Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-nextjs-production/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"readme":"# Next.js Production Engineering\n\n> Complete methodology for building, optimizing, and operating production Next.js applications. From architecture decisions to deployment strategies — everything beyond \"hello world.\"\n\n## Quick Health Check (60 seconds)\n\nRun through these 8 signals — score 0 (no) or 2 (yes):\n\n| Signal | Check | Score |\n|--------|-------|-------|\n| 🏗️ Architecture | Server/Client Component boundary is intentional, not accidental | /2 |\n| ⚡ Performance | Core Web Vitals all green (LCP <2.5s, INP <200ms, CLS <0.1) | /2 |\n| 🔒 Security | No secrets in client bundles, CSP headers configured | /2 |\n| 📦 Bundle | No unnecessary client JS, tree-shaking working | /2 |\n| 🗄️ Data | Caching strategy defined (not just defaults) | /2 |\n| 🧪 Testing | E2E + unit tests in CI, >70% coverage on critical paths | /2 |\n| 🚀 Deploy | Preview deploys, rollback capability, monitoring | /2 |\n| 📊 Observability | Error tracking, performance monitoring, structured logging | /2 |\n\n**Score:** /16 → 14-16 Production-ready | 10-13 Needs work | <10 Risk zone\n\n---\n\n## Phase 1: Architecture Decisions\n\n### App Router vs Pages Router Decision\n\n**Default: App Router** for all new projects (Next.js 13.4+).\n\nUse Pages Router ONLY if:\n- Migrating existing Pages Router app (incremental adoption)\n- Team has zero RSC experience AND shipping deadline <2 weeks\n- Library dependency requires Pages Router patterns\n\n### Project Structure (Recommended)\n\n```\nsrc/\n├── app/                    # App Router — routes only\n│   ├── (auth)/             # Route group — shared auth layout\n│   │   ├── login/page.tsx\n│   │   └── register/page.tsx\n│   ├── (dashboard)/        # Route group — shared dashboard layout\n│   │   ├── layout.tsx\n│   │   ├── page.tsx\n│   │   └── settings/page.tsx\n│   ├── api/                # Route Handlers (use sparingly)\n│   │   └── webhooks/\n│   │       └── stripe/route.ts\n│   ├── layout.tsx          # Root layout\n│   ├── loading.tsx         # Root loading\n│   ├── error.tsx           # Root error boundary\n│   ├── not-found.tsx       # 404 page\n│   └── global-error.tsx    # Global error boundary\n├── components/             # Shared components\n│   ├── ui/                 # Design system primitives\n│   ├── forms/              # Form components\n│   └── layouts/            # Layout components\n├── lib/                    # Shared utilities\n│   ├── db/                 # Database client & queries\n│   ├── auth/               # Auth utilities\n│   ├── api/                # External API clients\n│   └── utils/              # Pure utility functions\n├── hooks/                  # Custom React hooks (client-only)\n├── actions/                # Server Actions\n├── types/                  # TypeScript types\n├── styles/                 # Global styles\n└── config/                 # App configuration\n```\n\n### Structure Rules\n\n1. **Routes are thin** — `page.tsx` imports components, doesn't contain business logic\n2. **Components are reusable** — never import from `app/` into `components/`\n3. **Server Actions get their own directory** — organized by domain, not by page\n4. **No barrel files** (`index.ts` re-exports) — they break tree-shaking\n5. **Colocation for route-specific** — `_components/` in route folders for non-shared components\n\n### Rendering Strategy Decision Matrix\n\n| Scenario | Strategy | Why |\n|----------|----------|-----|\n| Static content (blog, docs, marketing) | Static (SSG) | Build-time generation, CDN-cached |\n| User-specific dashboard | Dynamic Server | Fresh data per request |\n| Product listing with prices | ISR (revalidate: 3600) | Fresh enough, fast delivery |\n| Real-time data (chat, stocks) | Client-side + WebSocket | Server can't push updates |\n| SEO-critical + fresh data | Dynamic Server + streaming | Fast TTFB with Suspense |\n| Highly interactive form/wizard | Client Component | Complex state management |\n\n### Server vs Client Component Rules\n\n```\nDEFAULT: Server Component (every .tsx is server by default)\n\nAdd \"use client\" ONLY when you need:\n✅ useState, useEffect, useRef, useContext\n✅ Browser APIs (window, document, localStorage)\n✅ Event handlers (onClick, onChange, onSubmit)\n✅ Third-party client libraries (framer-motion, react-hook-form)\n\nNEVER add \"use client\" because:\n❌ You want to use async/await (Server Components support this natively)\n❌ You're fetching data (fetch in Server Components, not useEffect)\n❌ You're importing a server-only library\n❌ \"It's not working\" — debug the actual issue first\n```\n\n### The Boundary Pattern\n\n```tsx\n// ✅ CORRECT: Server Component wraps Client Component\n// app/dashboard/page.tsx (Server Component)\nimport { getUser } from '@/lib/auth'\nimport { DashboardClient } from './_components/dashboard-client'\n\nexport default async function DashboardPage() {\n  const user = await getUser()  // Server-side data fetch\n  return <DashboardClient user={user} />  // Pass as props\n}\n\n// _components/dashboard-client.tsx\n'use client'\nexport function DashboardClient({ user }: { user: User }) {\n  const [tab, setTab] = useState('overview')\n  return <div>...</div>\n}\n```\n\n**Push \"use client\" as far down the tree as possible.** The boundary should be at the leaf, not the root.\n\n---\n\n## Phase 2: Data Fetching & Caching\n\n### Data Fetching Hierarchy (Prefer Top → Bottom)\n\n1. **Server Component direct fetch** — simplest, most performant\n2. **Server Actions** — for mutations and form submissions\n3. **Route Handlers** — for webhooks, external API endpoints\n4. **Client-side fetch (SWR/React Query)** — for real-time/polling data only\n\n### Fetch Configuration\n\n```tsx\n// Static data (cached indefinitely, revalidated on deploy)\nconst data = await fetch('https://api.example.com/data', {\n  cache: 'force-cache'  // Default in App Router\n})\n\n// Revalidate every hour\nconst data = await fetch('https://api.example.com/data', {\n  next: { revalidate: 3600 }\n})\n\n// Always fresh (no cache)\nconst data = await fetch('https://api.example.com/data', {\n  cache: 'no-store'\n})\n\n// Tag-based revalidation\nconst data = await fetch('https://api.example.com/products', {\n  next: { tags: ['products'] }\n})\n// Then in a Server Action:\nimport { revalidateTag } from 'next/cache'\nrevalidateTag('products')\n```\n\n### Caching Strategy by Data Type\n\n| Data Type | Cache Strategy | Revalidate | Tags |\n|-----------|---------------|------------|------|\n| CMS content | ISR | 3600s (1h) | `['cms', 'posts']` |\n| Product catalog | ISR | 300s (5m) | `['products']` |\n| User profile | No cache | — | — |\n| Pricing/inventory | No cache | — | — |\n| Static assets | Force cache | On deploy | — |\n| Analytics/dashboards | ISR | 60s | `['analytics']` |\n| Auth tokens | No cache | — | — |\n\n### Database Queries (No fetch API)\n\n```tsx\nimport { unstable_cache } from 'next/cache'\nimport { db } from '@/lib/db'\n\n// Cache database queries with tags\nconst getProducts = unstable_cache(\n  async (categoryId: string) => {\n    return db.query.products.findMany({\n      where: eq(products.categoryId, categoryId)\n    })\n  },\n  ['products'],  // Cache key parts\n  {\n    revalidate: 300,\n    tags: ['products']\n  }\n)\n```\n\n### Parallel Data Fetching\n\n```tsx\n// ✅ CORRECT: Parallel fetches\nexport default async function DashboardPage() {\n  const [user, stats, notifications] = await Promise.all([\n    getUser(),\n    getStats(),\n    getNotifications()\n  ])\n  return <Dashboard user={user} stats={stats} notifications={notifications} />\n}\n\n// ❌ WRONG: Sequential waterfall\nexport default async function DashboardPage() {\n  const user = await getUser()\n  const stats = await getStats(user.id)  // Waits for user\n  const notifications = await getNotifications(user.id)  // Waits for stats\n}\n```\n\n### Streaming with Suspense\n\n```tsx\nimport { Suspense } from 'react'\n\nexport default async function Page() {\n  return (\n    <div>\n      <h1>Dashboard</h1>\n      {/* Fast: renders immediately */}\n      <UserGreeting />\n      \n      {/* Slow: streams in when ready */}\n      <Suspense fallback={<StatsSkeleton />}>\n        <StatsPanel />  {/* Async Server Component */}\n      </Suspense>\n      \n      <Suspense fallback={<FeedSkeleton />}>\n        <ActivityFeed />\n      </Suspense>\n    </div>\n  )\n}\n```\n\n---\n\n## Phase 3: Server Actions & Mutations\n\n### Server Action Best Practices\n\n```tsx\n// actions/user.ts\n'use server'\n\nimport { z } from 'zod'\nimport { revalidatePath } from 'next/cache'\nimport { redirect } from 'next/navigation'\n\nconst updateProfileSchema = z.object({\n  name: z.string().min(1).max(100),\n  email: z.string().email(),\n  bio: z.string().max(500).optional()\n})\n\nexport async function updateProfile(formData: FormData) {\n  // 1. Authenticate\n  const session = await getSession()\n  if (!session) throw new Error('Unauthorized')\n\n  // 2. Validate\n  const parsed = updateProfileSchema.safeParse({\n    name: formData.get('name'),\n    email: formData.get('email'),\n    bio: formData.get('bio')\n  })\n  \n  if (!parsed.success) {\n    return { error: parsed.error.flatten().fieldErrors }\n  }\n\n  // 3. Authorize\n  if (session.userId !== formData.get('userId')) {\n    throw new Error('Forbidden')\n  }\n\n  // 4. Mutate\n  await db.update(users)\n    .set(parsed.data)\n    .where(eq(users.id, session.userId))\n\n  // 5. Revalidate\n  revalidatePath('/profile')\n  \n  return { success: true }\n}\n```\n\n### Server Action Rules\n\n1. **Always validate input** — FormData is user input, never trust it\n2. **Always check auth** — Server Actions are public endpoints\n3. **Always check authorization** — user can only modify their own data\n4. **Use Zod for validation** — type-safe, composable schemas\n5. **Return errors, don't throw** — throwing shows error boundary, returning shows inline errors\n6. **Revalidate after mutations** — `revalidatePath` or `revalidateTag`\n7. **Never return sensitive data** — return only what the client needs\n\n### useActionState Pattern (React 19)\n\n```tsx\n'use client'\nimport { useActionState } from 'react'\nimport { updateProfile } from '@/actions/user'\n\nexport function ProfileForm({ user }: { user: User }) {\n  const [state, action, pending] = useActionState(updateProfile, null)\n\n  return (\n    <form action={action}>\n      <input name=\"name\" defaultValue={user.name} />\n      {state?.error?.name && <p className=\"text-red-500\">{state.error.name}</p>}\n      \n      <button type=\"submit\" disabled={pending}>\n        {pending ? 'Saving...' : 'Save'}\n      </button>\n      \n      {state?.success && <p className=\"text-green-500\">Saved!</p>}\n    </form>\n  )\n}\n```\n\n---\n\n## Phase 4: Authentication & Authorization\n\n### Auth Pattern Selection\n\n| Method | Best For | Libraries |\n|--------|----------|-----------|\n| Session-based (cookie) | Traditional web apps | NextAuth.js / Auth.js |\n| JWT | API-first, mobile clients | jose, custom |\n| OAuth only | Social login, quick start | NextAuth.js |\n| Passkeys/WebAuthn | Modern, passwordless | SimpleWebAuthn |\n| Third-party | Enterprise, compliance | Clerk, Auth0, Supabase Auth |\n\n### Middleware Auth Pattern\n\n```tsx\n// middleware.ts\nimport { NextResponse } from 'next/server'\nimport type { NextRequest } from 'next/server'\n\nconst publicRoutes = ['/', '/login', '/register', '/api/webhooks']\nconst authRoutes = ['/login', '/register']\n\nexport function middleware(request: NextRequest) {\n  const { pathname } = request.nextUrl\n  const token = request.cookies.get('session')?.value\n\n  // Public routes — allow\n  if (publicRoutes.some(route => pathname.startsWith(route))) {\n    // Redirect authenticated users away from auth pages\n    if (token && authRoutes.some(route => pathname.startsWith(route))) {\n      return NextResponse.redirect(new URL('/dashboard', request.url))\n    }\n    return NextResponse.next()\n  }\n\n  // Protected routes — require auth\n  if (!token) {\n    const loginUrl = new URL('/login', request.url)\n    loginUrl.searchParams.set('callbackUrl', pathname)\n    return NextResponse.redirect(loginUrl)\n  }\n\n  return NextResponse.next()\n}\n\nexport const config = {\n  matcher: ['/((?!_next/static|_next/image|favicon.ico|public).*)']\n}\n```\n\n### Authorization Pattern\n\n```tsx\n// lib/auth/permissions.ts\ntype Permission = 'read' | 'write' | 'admin'\ntype Resource = 'posts' | 'users' | 'settings'\n\nconst rolePermissions: Record<string, Record<Resource, Permission[]>> = {\n  admin: {\n    posts: ['read', 'write', 'admin'],\n    users: ['read', 'write', 'admin'],\n    settings: ['read', 'write', 'admin']\n  },\n  editor: {\n    posts: ['read', 'write'],\n    users: ['read'],\n    settings: ['read']\n  },\n  viewer: {\n    posts: ['read'],\n    users: [],\n    settings: []\n  }\n}\n\nexport function can(role: string, resource: Resource, permission: Permission): boolean {\n  return rolePermissions[role]?.[resource]?.includes(permission) ?? false\n}\n\n// Usage in Server Component\nexport default async function AdminPage() {\n  const session = await getSession()\n  if (!can(session.role, 'settings', 'admin')) {\n    notFound()  // Don't reveal admin pages exist\n  }\n  return <AdminDashboard />\n}\n```\n\n### Security Headers (next.config.ts)\n\n```tsx\nconst securityHeaders = [\n  { key: 'X-DNS-Prefetch-Control', value: 'on' },\n  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },\n  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },\n  { key: 'X-Content-Type-Options', value: 'nosniff' },\n  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },\n  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },\n  {\n    key: 'Content-Security-Policy',\n    value: `\n      default-src 'self';\n      script-src 'self' 'unsafe-eval' 'unsafe-inline';\n      style-src 'self' 'unsafe-inline';\n      img-src 'self' data: https:;\n      font-src 'self';\n      connect-src 'self' https://api.example.com;\n      frame-ancestors 'none';\n    `.replace(/\\n/g, '')\n  }\n]\n```\n\n---\n\n## Phase 5: Performance Optimization\n\n### Core Web Vitals Targets\n\n| Metric | Good | Needs Improvement | Poor |\n|--------|------|-------------------|------|\n| LCP | <2.5s | 2.5-4.0s | >4.0s |\n| INP | <200ms | 200-500ms | >500ms |\n| CLS | <0.1 | 0.1-0.25 | >0.25 |\n| TTFB | <800ms | 800ms-1.8s | >1.8s |\n| FCP | <1.8s | 1.8-3.0s | >3.0s |\n\n### Image Optimization\n\n```tsx\nimport Image from 'next/image'\n\n// ✅ Always use next/image\n<Image\n  src=\"/hero.jpg\"\n  alt=\"Hero image\"\n  width={1200}\n  height={630}\n  priority  // LCP image — load immediately\n  sizes=\"(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw\"\n  placeholder=\"blur\"\n  blurDataURL={shimmer}  // Base64 placeholder\n/>\n\n// For dynamic images\n<Image\n  src={user.avatar}\n  alt={user.name}\n  width={48}\n  height={48}\n  loading=\"lazy\"  // Below fold — lazy load\n/>\n```\n\n### Image Rules\n\n1. **Always set `priority` on LCP image** (hero, above-fold)\n2. **Always provide `sizes`** — prevents downloading oversized images\n3. **Use `placeholder=\"blur\"`** for large images — prevents CLS\n4. **Configure `remotePatterns`** in next.config.ts for external images\n5. **Use WebP/AVIF** — next/image auto-converts by default\n\n### Bundle Optimization\n\n```tsx\n// next.config.ts\nconst nextConfig = {\n  // Strict mode for catching bugs\n  reactStrictMode: true,\n  \n  // Optimize packages\n  experimental: {\n    optimizePackageImports: [\n      'lucide-react',\n      '@radix-ui/react-icons',\n      'date-fns',\n      'lodash-es'\n    ]\n  },\n  \n  // Bundle analyzer (dev only)\n  // npm install @next/bundle-analyzer\n  ...(process.env.ANALYZE === 'true' && {\n    webpack: (config) => {\n      const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')\n      config.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'static' }))\n      return config\n    }\n  })\n}\n```\n\n### Dynamic Imports for Heavy Components\n\n```tsx\nimport dynamic from 'next/dynamic'\n\n// Heavy chart library — only load when needed\nconst Chart = dynamic(() => import('@/components/chart'), {\n  loading: () => <ChartSkeleton />,\n  ssr: false  // Client-only component\n})\n\n// Code editor — definitely client-only\nconst CodeEditor = dynamic(() => import('@/components/code-editor'), {\n  ssr: false\n})\n```\n\n### Font Optimization\n\n```tsx\n// app/layout.tsx\nimport { Inter, JetBrains_Mono } from 'next/font/google'\n\nconst inter = Inter({\n  subsets: ['latin'],\n  display: 'swap',\n  variable: '--font-inter'\n})\n\nconst jetbrains = JetBrains_Mono({\n  subsets: ['latin'],\n  display: 'swap',\n  variable: '--font-mono'\n})\n\nexport default function RootLayout({ children }) {\n  return (\n    <html lang=\"en\" className={`${inter.variable} ${jetbrains.variable}`}>\n      <body className=\"font-sans\">{children}</body>\n    </html>\n  )\n}\n```\n\n### Performance Budget\n\n| Resource | Budget | Tool |\n|----------|--------|------|\n| First Load JS | <100KB | `next build` output |\n| Page JS | <50KB per route | Bundle analyzer |\n| Total page weight | <500KB | Lighthouse |\n| LCP image | <200KB | next/image handles |\n| Third-party scripts | <50KB total | Script component |\n| Web fonts | <100KB | next/font handles |\n\n---\n\n## Phase 6: Database & ORM\n\n### ORM Selection Guide\n\n| ORM | Best For | Tradeoffs |\n|-----|----------|-----------|\n| Drizzle | Type-safe, lightweight, SQL-like | Newer ecosystem |\n| Prisma | Rapid prototyping, schema-first | Heavier, edge limitations |\n| Kysely | Type-safe raw SQL | More manual, no migrations |\n| Raw SQL (pg/mysql2) | Max performance, full control | No type safety, manual migrations |\n\n### Drizzle Setup Pattern (Recommended)\n\n```tsx\n// lib/db/index.ts\nimport { drizzle } from 'drizzle-orm/node-postgres'\nimport { Pool } from 'pg'\nimport * as schema from './schema'\n\nconst pool = new Pool({\n  connectionString: process.env.DATABASE_URL,\n  max: 20,\n  idleTimeoutMillis: 30000\n})\n\nexport const db = drizzle(pool, { schema })\n\n// lib/db/schema.ts\nimport { pgTable, text, timestamp, uuid, boolean } from 'drizzle-orm/pg-core'\n\nexport const users = pgTable('users', {\n  id: uuid('id').defaultRandom().primaryKey(),\n  email: text('email').notNull().unique(),\n  name: text('name').notNull(),\n  role: text('role', { enum: ['admin', 'editor', 'viewer'] }).default('viewer'),\n  emailVerified: boolean('email_verified').default(false),\n  createdAt: timestamp('created_at').defaultNow(),\n  updatedAt: timestamp('updated_at').defaultNow()\n})\n```\n\n### Connection Pooling for Serverless\n\n```tsx\n// For Vercel/serverless — use connection pooler\n// Neon: use pooler URL (port 5432 → 6543)\n// Supabase: use Supavisor URL\n// PlanetScale: serverless driver built-in\n\n// lib/db/index.ts (serverless-safe)\nimport { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'\n\nconst sql = neon(process.env.DATABASE_URL!)\nexport const db = drizzle(sql)\n```\n\n---\n\n## Phase 7: Testing Strategy\n\n### Test Pyramid for Next.js\n\n| Level | Tool | What to Test | Coverage Target |\n|-------|------|-------------|-----------------|\n| Unit | Vitest | Utils, hooks, pure functions | 80%+ |\n| Component | Testing Library + Vitest | UI components, forms | 70%+ |\n| Integration | Testing Library | Page-level with mocked data | Key flows |\n| E2E | Playwright | Critical user journeys | 5-10 flows |\n| Visual | Playwright screenshots | UI regression | Key pages |\n\n### Vitest Configuration\n\n```tsx\n// vitest.config.ts\nimport { defineConfig } from 'vitest/config'\nimport react from '@vitejs/plugin-react'\nimport tsconfigPaths from 'vite-tsconfig-paths'\n\nexport default defineConfig({\n  plugins: [react(), tsconfigPaths()],\n  test: {\n    environment: 'jsdom',\n    setupFiles: ['./tests/setup.ts'],\n    include: ['**/*.test.{ts,tsx}'],\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'lcov'],\n      exclude: ['**/*.config.*', '**/types/**']\n    }\n  }\n})\n```\n\n### Server Component Testing\n\n```tsx\n// Server Components can be tested as async functions\nimport { render } from '@testing-library/react'\nimport Page from '@/app/dashboard/page'\n\n// Mock the data fetching\nvi.mock('@/lib/db', () => ({\n  getUser: vi.fn().mockResolvedValue({ id: '1', name: 'Test' })\n}))\n\ntest('dashboard page renders user name', async () => {\n  const Component = await Page()  // Call as async function\n  const { getByText } = render(Component)\n  expect(getByText('Test')).toBeInTheDocument()\n})\n```\n\n### Playwright E2E Pattern\n\n```tsx\n// e2e/auth.spec.ts\nimport { test, expect } from '@playwright/test'\n\ntest.describe('Authentication', () => {\n  test('login flow', async ({ page }) => {\n    await page.goto('/login')\n    await page.fill('[name=\"email\"]', 'test@example.com')\n    await page.fill('[name=\"password\"]', 'password123')\n    await page.click('button[type=\"submit\"]')\n    \n    await expect(page).toHaveURL('/dashboard')\n    await expect(page.getByText('Welcome')).toBeVisible()\n  })\n  \n  test('protected route redirects', async ({ page }) => {\n    await page.goto('/dashboard')\n    await expect(page).toHaveURL(/\\/login/)\n  })\n})\n```\n\n---\n\n## Phase 8: Error Handling & Monitoring\n\n### Error Boundary Architecture\n\n```\napp/\n├── global-error.tsx     # Catches root layout errors (must include <html>)\n├── error.tsx            # Catches app-level errors\n├── not-found.tsx        # 404 page\n├── (dashboard)/\n│   ├── error.tsx        # Dashboard-specific errors\n│   └── settings/\n│       └── error.tsx    # Settings-specific errors\n```\n\n### Error Component Pattern\n\n```tsx\n// app/error.tsx\n'use client'\n\nimport { useEffect } from 'react'\n\nexport default function Error({\n  error,\n  reset,\n}: {\n  error: Error & { digest?: string }\n  reset: () => void\n}) {\n  useEffect(() => {\n    // Log to error tracking service\n    console.error('Application error:', error)\n    // Sentry.captureException(error)\n  }, [error])\n\n  return (\n    <div className=\"flex flex-col items-center justify-center min-h-[400px]\">\n      <h2 className=\"text-2xl font-bold\">Something went wrong</h2>\n      <p className=\"text-gray-500 mt-2\">\n        {error.digest ? `Error ID: ${error.digest}` : error.message}\n      </p>\n      <button\n        onClick={reset}\n        className=\"mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700\"\n      >\n        Try again\n      </button>\n    </div>\n  )\n}\n```\n\n### Structured Logging\n\n```tsx\n// lib/logger.ts\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nfunction log(level: LogLevel, message: string, meta?: Record<string, unknown>) {\n  const entry = {\n    timestamp: new Date().toISOString(),\n    level,\n    message,\n    ...meta,\n    // Add request context if available\n    ...(meta?.requestId && { requestId: meta.requestId })\n  }\n  \n  if (level === 'error') {\n    console.error(JSON.stringify(entry))\n  } else {\n    console.log(JSON.stringify(entry))\n  }\n}\n\nexport const logger = {\n  debug: (msg: string, meta?: Record<string, unknown>) => log('debug', msg, meta),\n  info: (msg: string, meta?: Record<string, unknown>) => log('info', msg, meta),\n  warn: (msg: string, meta?: Record<string, unknown>) => log('warn', msg, meta),\n  error: (msg: string, meta?: Record<string, unknown>) => log('error', msg, meta)\n}\n```\n\n---\n\n## Phase 9: Deployment & Infrastructure\n\n### Platform Comparison\n\n| Platform | Best For | Edge | DB | Cost (hobby) |\n|----------|----------|------|-----|---------------|\n| Vercel | Default choice, best DX | ✅ | External | Free → $20/mo |\n| Cloudflare Pages | Edge-first, Workers | ✅ | D1, KV | Free → $5/mo |\n| AWS Amplify | AWS ecosystem | ✅ | RDS, DynamoDB | Pay-per-use |\n| Railway | Full-stack, Docker | ❌ | Built-in Postgres | $5/mo |\n| Fly.io | Global, Docker | ✅ | Built-in Postgres | Pay-per-use |\n| Self-hosted (Docker) | Full control | ❌ | Any | Server cost |\n\n### Docker Production Setup\n\n```dockerfile\n# Dockerfile\nFROM node:20-alpine AS base\nRUN corepack enable\n\nFROM base AS deps\nWORKDIR /app\nCOPY package.json pnpm-lock.yaml ./\nRUN pnpm install --frozen-lockfile\n\nFROM base AS builder\nWORKDIR /app\nCOPY --from=deps /app/node_modules ./node_modules\nCOPY . .\nENV NEXT_TELEMETRY_DISABLED=1\nRUN pnpm build\n\nFROM base AS runner\nWORKDIR /app\nENV NODE_ENV=production\nENV NEXT_TELEMETRY_DISABLED=1\n\nRUN addgroup --system --gid 1001 nodejs\nRUN adduser --system --uid 1001 nextjs\n\nCOPY --from=builder /app/public ./public\nCOPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./\nCOPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static\n\nUSER nextjs\nEXPOSE 3000\nENV PORT=3000\nENV HOSTNAME=\"0.0.0.0\"\n\nCMD [\"node\", \"server.js\"]\n```\n\n```tsx\n// next.config.ts — required for standalone\nconst nextConfig = {\n  output: 'standalone'\n}\n```\n\n### CI/CD Pipeline (GitHub Actions)\n\n```yaml\n# .github/workflows/ci.yml\nname: CI\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  quality:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: pnpm/action-setup@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 20\n          cache: pnpm\n      - run: pnpm install --frozen-lockfile\n      - run: pnpm tsc --noEmit\n      - run: pnpm lint\n      - run: pnpm test -- --coverage\n      - run: pnpm build\n      \n  e2e:\n    runs-on: ubuntu-latest\n    needs: quality\n    steps:\n      - uses: actions/checkout@v4\n      - uses: pnpm/action-setup@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 20\n          cache: pnpm\n      - run: pnpm install --frozen-lockfile\n      - run: pnpm exec playwright install --with-deps\n      - run: pnpm build\n      - run: pnpm exec playwright test\n      - uses: actions/upload-artifact@v4\n        if: failure()\n        with:\n          name: playwright-report\n          path: playwright-report/\n```\n\n### Environment Variables\n\n```tsx\n// env.ts — runtime validation with t3-env\nimport { createEnv } from '@t3-oss/env-nextjs'\nimport { z } from 'zod'\n\nexport const env = createEnv({\n  server: {\n    DATABASE_URL: z.string().url(),\n    AUTH_SECRET: z.string().min(32),\n    STRIPE_SECRET_KEY: z.string().startsWith('sk_'),\n    REDIS_URL: z.string().url().optional(),\n  },\n  client: {\n    NEXT_PUBLIC_APP_URL: z.string().url(),\n    NEXT_PUBLIC_STRIPE_KEY: z.string().startsWith('pk_'),\n  },\n  runtimeEnv: {\n    DATABASE_URL: process.env.DATABASE_URL,\n    AUTH_SECRET: process.env.AUTH_SECRET,\n    STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,\n    REDIS_URL: process.env.REDIS_URL,\n    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,\n    NEXT_PUBLIC_STRIPE_KEY: process.env.NEXT_PUBLIC_STRIPE_KEY,\n  },\n})\n```\n\n---\n\n## Phase 10: Common Patterns Library\n\n### Optimistic Updates\n\n```tsx\n'use client'\nimport { useOptimistic, useTransition } from 'react'\nimport { toggleTodo } from '@/actions/todos'\n\nexport function TodoItem({ todo }: { todo: Todo }) {\n  const [optimisticTodo, setOptimisticTodo] = useOptimistic(todo)\n  const [, startTransition] = useTransition()\n\n  return (\n    <label>\n      <input\n        type=\"checkbox\"\n        checked={optimisticTodo.completed}\n        onChange={() => {\n          startTransition(async () => {\n            setOptimisticTodo({ ...todo, completed: !todo.completed })\n            await toggleTodo(todo.id)\n          })\n        }}\n      />\n      {optimisticTodo.title}\n    </label>\n  )\n}\n```\n\n### Infinite Scroll\n\n```tsx\n'use client'\nimport { useInView } from 'react-intersection-observer'\nimport { useEffect, useState, useTransition } from 'react'\nimport { loadMore } from '@/actions/feed'\n\nexport function InfiniteList({ initialItems }: { initialItems: Item[] }) {\n  const [items, setItems] = useState(initialItems)\n  const [cursor, setCursor] = useState(initialItems.at(-1)?.id)\n  const [hasMore, setHasMore] = useState(true)\n  const [isPending, startTransition] = useTransition()\n  const { ref, inView } = useInView()\n\n  useEffect(() => {\n    if (inView && hasMore && !isPending) {\n      startTransition(async () => {\n        const newItems = await loadMore(cursor)\n        if (newItems.length === 0) {\n          setHasMore(false)\n        } else {\n          setItems(prev => [...prev, ...newItems])\n          setCursor(newItems.at(-1)?.id)\n        }\n      })\n    }\n  }, [inView, hasMore, isPending, cursor])\n\n  return (\n    <div>\n      {items.map(item => <ItemCard key={item.id} item={item} />)}\n      {hasMore && <div ref={ref}>{isPending ? <Spinner /> : null}</div>}\n    </div>\n  )\n}\n```\n\n### Search with URL State\n\n```tsx\n'use client'\nimport { useRouter, useSearchParams, usePathname } from 'next/navigation'\nimport { useDebouncedCallback } from 'use-debounce'\n\nexport function SearchBar() {\n  const router = useRouter()\n  const pathname = usePathname()\n  const searchParams = useSearchParams()\n\n  const handleSearch = useDebouncedCallback((term: string) => {\n    const params = new URLSearchParams(searchParams)\n    if (term) {\n      params.set('q', term)\n      params.set('page', '1')\n    } else {\n      params.delete('q')\n    }\n    router.replace(`${pathname}?${params.toString()}`)\n  }, 300)\n\n  return (\n    <input\n      type=\"search\"\n      placeholder=\"Search...\"\n      defaultValue={searchParams.get('q') ?? ''}\n      onChange={e => handleSearch(e.target.value)}\n    />\n  )\n}\n```\n\n### Multi-step Form with URL State\n\n```tsx\n// app/onboarding/page.tsx\nexport default function OnboardingPage({\n  searchParams\n}: {\n  searchParams: { step?: string }\n}) {\n  const step = Number(searchParams.step) || 1\n  \n  return (\n    <div>\n      <ProgressBar step={step} total={4} />\n      {step === 1 && <StepOne />}\n      {step === 2 && <StepTwo />}\n      {step === 3 && <StepThree />}\n      {step === 4 && <StepFour />}\n    </div>\n  )\n}\n```\n\n---\n\n## Phase 11: Production Checklist\n\n### Pre-Launch (Mandatory)\n\n- [ ] `next build` succeeds with zero warnings\n- [ ] TypeScript strict mode, no `any` types in production code\n- [ ] All environment variables validated (t3-env or manual)\n- [ ] Security headers configured (CSP, HSTS, X-Frame-Options)\n- [ ] Authentication + authorization tested (pen test critical flows)\n- [ ] Error boundaries at every route level\n- [ ] 404 and 500 pages customized\n- [ ] Favicon, OG images, meta tags configured\n- [ ] Core Web Vitals passing (Lighthouse >90)\n- [ ] Mobile responsive tested on real devices\n- [ ] Accessibility audit (axe, keyboard nav, screen reader)\n- [ ] Rate limiting on API routes and Server Actions\n- [ ] CORS configured correctly\n- [ ] Database connection pooling configured for serverless\n- [ ] Monitoring & error tracking connected (Sentry, etc.)\n\n### Pre-Launch (Recommended)\n\n- [ ] E2E tests for critical user journeys\n- [ ] Bundle size within budget (<100KB first load)\n- [ ] Image optimization verified (next/image, proper sizes)\n- [ ] Sitemap.xml and robots.txt configured\n- [ ] Analytics configured\n- [ ] Preview deployment tested\n- [ ] Rollback plan documented\n- [ ] Load testing completed\n- [ ] CDN caching verified\n- [ ] Edge middleware tested in production environment\n\n---\n\n## Phase 12: Anti-Patterns & Troubleshooting\n\n### 10 Next.js Mistakes\n\n| # | Mistake | Fix |\n|---|---------|-----|\n| 1 | `\"use client\"` at the top of every file | Default to Server Components, push client boundary down |\n| 2 | Fetching data with useEffect | Fetch in Server Components or use SWR/React Query for client |\n| 3 | Not using `loading.tsx` | Add loading states to prevent layout shift |\n| 4 | Ignoring bundle size | Run `next build` and check output, use dynamic imports |\n| 5 | No error boundaries | Add `error.tsx` at every route level |\n| 6 | Storing secrets in `NEXT_PUBLIC_*` | Server-only env vars for secrets, validate with t3-env |\n| 7 | Not setting image `sizes` prop | Always provide `sizes` for responsive images |\n| 8 | Sequential data fetching | Use `Promise.all()` for parallel fetches |\n| 9 | Caching everything or nothing | Explicit cache strategy per data type |\n| 10 | Not using `revalidateTag` | Tag-based revalidation for precise cache control |\n\n### Troubleshooting Decision Tree\n\n```\nBuild error?\n├── \"Module not found\" → Check import paths, tsconfig paths\n├── \"Server Component error\" → Remove \"use client\" or move hooks to client component\n├── \"Hydration mismatch\" → Check for browser-only code in shared components\n│   → Use suppressHydrationWarning for timestamps\n│   → Wrap in useEffect or dynamic(ssr: false)\n├── \"Edge runtime error\" → Check node APIs (fs, crypto) not available at edge\n└── Slow build → Check for large static generation, reduce ISR pages\n\nRuntime error?\n├── 500 on production → Check error.tsx, logs, Sentry\n├── Slow TTFB → Check database queries, add caching\n├── CLS → Add explicit dimensions to images/embeds\n├── High JS bundle → Run bundle analyzer, dynamic import heavy libs\n└── Stale data → Check revalidation settings, revalidateTag\n```\n\n---\n\n## Recommended Stack (2025+)\n\n| Layer | Recommendation | Why |\n|-------|---------------|-----|\n| Framework | Next.js 15+ (App Router) | RSC, streaming, Server Actions |\n| Language | TypeScript (strict) | Type safety, better DX |\n| Styling | Tailwind CSS 4 | Utility-first, no runtime cost |\n| UI Components | shadcn/ui | Copy-paste, customizable |\n| Forms | react-hook-form + zod | Type-safe validation |\n| ORM | Drizzle | Type-safe, lightweight, SQL-like |\n| Database | PostgreSQL (Neon/Supabase) | Serverless-friendly, proven |\n| Auth | Auth.js (NextAuth v5) | Built for Next.js |\n| Payments | Stripe | Industry standard |\n| Hosting | Vercel | Best Next.js DX |\n| Testing | Vitest + Playwright | Fast unit + reliable E2E |\n| Monitoring | Sentry | Error tracking + performance |\n| Analytics | PostHog | Product analytics, open source |\n\n---\n\n## Quality Rubric (0-100)\n\n| Dimension | Weight | Scoring |\n|-----------|--------|---------|\n| Architecture (RSC boundaries, structure) | 20% | 0-20 |\n| Performance (CWV, bundle, TTFB) | 20% | 0-20 |\n| Security (auth, headers, validation) | 15% | 0-15 |\n| Data layer (caching, fetching, DB) | 15% | 0-15 |\n| Testing (pyramid, coverage, E2E) | 10% | 0-10 |\n| Error handling (boundaries, logging) | 10% | 0-10 |\n| DX (types, linting, CI) | 5% | 0-5 |\n| Deployment (Docker/platform, monitoring) | 5% | 0-5 |\n\n**Score:** 90-100 Elite | 75-89 Production-ready | 60-74 Needs improvement | <60 Not production-ready\n\n---\n\n## Natural Language Commands\n\n1. \"Set up a new Next.js project\" → Phase 1 architecture + structure + Phase 6 DB setup\n2. \"Add authentication\" → Phase 4 auth pattern + middleware + authorization\n3. \"Optimize performance\" → Phase 5 full checklist + image + bundle + fonts\n4. \"Set up testing\" → Phase 7 full pyramid + Vitest + Playwright config\n5. \"Deploy to production\" → Phase 9 platform selection + Docker + CI/CD + env vars\n6. \"Fix hydration error\" → Phase 12 troubleshooting tree\n7. \"Add caching\" → Phase 2 caching strategy table + fetch config + tags\n8. \"Create a Server Action\" → Phase 3 best practices + useActionState pattern\n9. \"Audit my app\" → Quick health check + Phase 11 production checklist\n10. \"Add error handling\" → Phase 8 error boundary architecture + logging\n11. \"Set up search\" → Phase 10 search with URL state pattern\n12. \"Review my architecture\" → Phase 1 decision matrix + rendering strategy\n\n---\n\n*Built by AfrexAI — the AI automation agency that ships. Zero dependencies.*\n","readmeExcerpt":"Next.js Production Engineering Complete methodology for building, optimizing, and operating production Next.js applications. From architecture decisions to deployment strategies — everything beyond \"hello world.\" Quick Health Check (60 seconds) Run through these 8 signals — score 0 (no) or 2 (yes): | Signal | Check | Score | |--------|-------|-------| | 🏗️ Architecture | Server/Client Component boundary is intention","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"src/\n├── app/                    # App Router — routes only\n│   ├── (auth)/             # Route group — shared auth layout\n│   │   ├── login/page.tsx\n│   │   └── register/page.tsx\n│   ├── (dashboard)/        # Route group — shared dashboard layout\n│   │   ├── layout.tsx\n│   │   ├── page.tsx\n│   │   └── settings/page.tsx\n│   ├── api/                # Route Handlers (use sparingly)\n│   │   └── webhooks/\n│   │       └── stripe/route.ts\n│   ├── layout.tsx          # Root layout\n│   ├── loading.tsx         # Root loading\n│   ├── error.tsx           # Root error boundary\n│   ├── not-found.tsx       # 404 page\n│   └── global-error.tsx    # Global error boundary\n├── components/             # Shared components\n│   ├── ui/                 # Design system primitives\n│   ├── forms/              # Form components\n│   └── layouts/            # Layout components\n├── lib/                    # Shared utilities\n│   ├── db/                 # Database client & queries\n│   ├── auth/               # Auth utilities\n│   ├── api/                # External API clients\n│   └── utils/              # Pure utility functions\n├── hooks/                  # Custom React hooks (client-only)\n├── actions/                # Server Actions\n├── types/                  # TypeScript types\n├── styles/                 # Global styles\n└── config/                 # App configuration"},{"language":"text","snippet":"DEFAULT: Server Component (every .tsx is server by default)\n\nAdd \"use client\" ONLY when you need:\n✅ useState, useEffect, useRef, useContext\n✅ Browser APIs (window, document, localStorage)\n✅ Event handlers (onClick, onChange, onSubmit)\n✅ Third-party client libraries (framer-motion, react-hook-form)\n\nNEVER add \"use client\" because:\n❌ You want to use async/await (Server Components support this natively)\n❌ You're fetching data (fetch in Server Components, not useEffect)\n❌ You're importing a server-only library\n❌ \"It's not working\" — debug the actual issue first"},{"language":"tsx","snippet":"// ✅ CORRECT: Server Component wraps Client Component\n// app/dashboard/page.tsx (Server Component)\nimport { getUser } from '@/lib/auth'\nimport { DashboardClient } from './_components/dashboard-client'\n\nexport default async function DashboardPage() {\n  const user = await getUser()  // Server-side data fetch\n  return <DashboardClient user={user} />  // Pass as props\n}\n\n// _components/dashboard-client.tsx\n'use client'\nexport function DashboardClient({ user }: { user: User }) {\n  const [tab, setTab] = useState('overview')\n  return <div>...</div>\n}"},{"language":"tsx","snippet":"// Static data (cached indefinitely, revalidated on deploy)\nconst data = await fetch('https://api.example.com/data', {\n  cache: 'force-cache'  // Default in App Router\n})\n\n// Revalidate every hour\nconst data = await fetch('https://api.example.com/data', {\n  next: { revalidate: 3600 }\n})\n\n// Always fresh (no cache)\nconst data = await fetch('https://api.example.com/data', {\n  cache: 'no-store'\n})\n\n// Tag-based revalidation\nconst data = await fetch('https://api.example.com/products', {\n  next: { tags: ['products'] }\n})\n// Then in a Server Action:\nimport { revalidateTag } from 'next/cache'\nrevalidateTag('products')"},{"language":"tsx","snippet":"import { unstable_cache } from 'next/cache'\nimport { db } from '@/lib/db'\n\n// Cache database queries with tags\nconst getProducts = unstable_cache(\n  async (categoryId: string) => {\n    return db.query.products.findMany({\n      where: eq(products.categoryId, categoryId)\n    })\n  },\n  ['products'],  // Cache key parts\n  {\n    revalidate: 300,\n    tags: ['products']\n  }\n)"},{"language":"tsx","snippet":"// ✅ CORRECT: Parallel fetches\nexport default async function DashboardPage() {\n  const [user, stats, notifications] = await Promise.all([\n    getUser(),\n    getStats(),\n    getNotifications()\n  ])\n  return <Dashboard user={user} stats={stats} notifications={notifications} />\n}\n\n// ❌ WRONG: Sequential waterfall\nexport default async function DashboardPage() {\n  const user = await getUser()\n  const stats = await getStats(user.id)  // Waits for user\n  const notifications = await getNotifications(user.id)  // Waits for stats\n}"}],"parameters":{},"dependencies":[],"permissions":[],"extractedFiles":[],"languages":["typescript"],"docsSourceLabel":"CLAWHUB","editorialOverview":"Next.js Production Engineering Next.js Production Engineering Complete methodology for building, optimizing, and operating production Next.js applications. From architecture decisions to deployment strategies — everything beyond \"hello world.\" Quick Health Check (60 seconds) Run through these 8 signals — score 0 (no) or 2 (yes): | Signal | Check | Score | |--------|-------|-------| | 🏗️ Architecture | Server/Client Component boundary is intention","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":366,"uniquenessScore":67,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T07:50:26.576Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}