From 132e79df89ecc4ca0a9c7313c7515c978e4e5f97 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Tue, 12 May 2026 19:05:13 +0200 Subject: [PATCH] chore(skills): update Next.js guidance to version 16 (#11143) --- AGENTS.md | 14 +++- prowler/AGENTS.md | 4 + skills/README.md | 2 +- skills/nextjs-15/SKILL.md | 150 ---------------------------------- skills/nextjs-16/SKILL.md | 160 +++++++++++++++++++++++++++++++++++++ skills/prowler-ui/SKILL.md | 6 +- skills/prowler/SKILL.md | 2 +- skills/react-19/SKILL.md | 2 +- ui/AGENTS.md | 6 +- 9 files changed, 184 insertions(+), 162 deletions(-) delete mode 100644 skills/nextjs-15/SKILL.md create mode 100644 skills/nextjs-16/SKILL.md diff --git a/AGENTS.md b/AGENTS.md index 1d7a36c667..47b7e12dcb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ Use these skills for detailed patterns on-demand: |-------|-------------|-----| | `typescript` | Const types, flat interfaces, utility types | [SKILL.md](skills/typescript/SKILL.md) | | `react-19` | No useMemo/useCallback, React Compiler | [SKILL.md](skills/react-19/SKILL.md) | -| `nextjs-15` | App Router, Server Actions, streaming | [SKILL.md](skills/nextjs-15/SKILL.md) | +| `nextjs-16` | App Router, Server Actions, proxy.ts, streaming | [SKILL.md](skills/nextjs-16/SKILL.md) | | `tailwind-4` | cn() utility, no var() in className | [SKILL.md](skills/tailwind-4/SKILL.md) | | `playwright` | Page Object Model, MCP workflow, selectors | [SKILL.md](skills/playwright/SKILL.md) | | `pytest` | Fixtures, mocking, markers, parametrize | [SKILL.md](skills/pytest/SKILL.md) | @@ -60,11 +60,14 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: |--------|-------| | Add changelog entry for a PR or feature | `prowler-changelog` | | Adding DRF pagination or permissions | `django-drf` | +| Adding a compliance output formatter (per-provider class + table dispatcher) | `prowler-compliance` | +| Adding indexes or constraints to database tables | `django-migration-psql` | | Adding new providers | `prowler-provider` | | Adding privilege escalation detection queries | `prowler-attack-paths-query` | | Adding services to existing providers | `prowler-provider` | | After creating/modifying a skill | `skill-sync` | -| App Router / Server Actions | `nextjs-15` | +| App Router / Server Actions | `nextjs-16` | +| Auditing check-to-requirement mappings as a cloud auditor | `prowler-compliance` | | Building AI chat features | `ai-sdk-5` | | Committing changes | `prowler-commit` | | Configuring MCP servers in agentic workflows | `gh-aw` | @@ -78,6 +81,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Creating a git commit | `prowler-commit` | | Creating new checks | `prowler-sdk-check` | | Creating new skills | `skill-creator` | +| Creating or reviewing Django migrations | `django-migration-psql` | | Creating/modifying Prowler UI components | `prowler-ui` | | Creating/modifying models, views, serializers | `prowler-api` | | Creating/updating compliance frameworks | `prowler-compliance` | @@ -85,6 +89,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Debugging gh-aw compilation errors | `gh-aw` | | Fill .github/pull_request_template.md (Context/Description/Steps to review/Checklist) | `prowler-pr` | | Fixing bug | `tdd` | +| Fixing compliance JSON bugs (duplicate IDs, empty Section, stale refs) | `prowler-compliance` | | General Prowler development questions | `prowler` | | Implementing JSON:API endpoints | `django-drf` | | Implementing feature | `tdd` | @@ -102,6 +107,8 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Review changelog format and conventions | `prowler-changelog` | | Reviewing JSON:API compliance | `jsonapi` | | Reviewing compliance framework PRs | `prowler-compliance-review` | +| Running makemigrations or pgmakemigrations | `django-migration-psql` | +| Syncing compliance framework with upstream catalog | `prowler-compliance` | | Testing RLS tenant isolation | `prowler-test-api` | | Testing hooks or utilities | `vitest` | | Troubleshoot why a skill is missing from AGENTS.md auto-invoke | `skill-sync` | @@ -129,6 +136,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Writing React components | `react-19` | | Writing TypeScript types/interfaces | `typescript` | | Writing Vitest tests | `vitest` | +| Writing data backfill or data migration | `django-migration-psql` | | Writing documentation | `prowler-docs` | | Writing unit tests for UI | `vitest` | @@ -142,7 +150,7 @@ Prowler is an open-source cloud security assessment tool supporting AWS, Azure, |-----------|----------|------------| | SDK | `prowler/` | Python 3.10+, Poetry 2.3+ | | API | `api/` | Django 5.1, DRF, Celery | -| UI | `ui/` | Next.js 15, React 19, Tailwind 4 | +| UI | `ui/` | Next.js 16, React 19, Tailwind 4 | | MCP Server | `mcp_server/` | FastMCP, Python 3.12+ | | Dashboard | `dashboard/` | Dash, Plotly | diff --git a/prowler/AGENTS.md b/prowler/AGENTS.md index 5f7099ac0a..cccf95b135 100644 --- a/prowler/AGENTS.md +++ b/prowler/AGENTS.md @@ -14,15 +14,19 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Action | Skill | |--------|-------| | Add changelog entry for a PR or feature | `prowler-changelog` | +| Adding a compliance output formatter (per-provider class + table dispatcher) | `prowler-compliance` | | Adding new providers | `prowler-provider` | | Adding services to existing providers | `prowler-provider` | +| Auditing check-to-requirement mappings as a cloud auditor | `prowler-compliance` | | Create PR that requires changelog entry | `prowler-changelog` | | Creating new checks | `prowler-sdk-check` | | Creating/updating compliance frameworks | `prowler-compliance` | +| Fixing compliance JSON bugs (duplicate IDs, empty Section, stale refs) | `prowler-compliance` | | Mapping checks to compliance controls | `prowler-compliance` | | Mocking AWS with moto in tests | `prowler-test-sdk` | | Review changelog format and conventions | `prowler-changelog` | | Reviewing compliance framework PRs | `prowler-compliance-review` | +| Syncing compliance framework with upstream catalog | `prowler-compliance` | | Update CHANGELOG.md in any component | `prowler-changelog` | | Updating existing checks and metadata | `prowler-sdk-check` | | Writing Prowler SDK tests | `prowler-test-sdk` | diff --git a/skills/README.md b/skills/README.md index 1d689962af..999760d079 100644 --- a/skills/README.md +++ b/skills/README.md @@ -50,7 +50,7 @@ Reusable patterns for common technologies: |-------|-------------| | `typescript` | Const types, flat interfaces, utility types | | `react-19` | React 19 patterns, React Compiler | -| `nextjs-15` | App Router, Server Actions, streaming | +| `nextjs-16` | App Router, Server Actions, proxy.ts, streaming | | `tailwind-4` | cn() utility, Tailwind 4 patterns | | `playwright` | Page Object Model, selectors | | `vitest` | Unit testing, React Testing Library | diff --git a/skills/nextjs-15/SKILL.md b/skills/nextjs-15/SKILL.md deleted file mode 100644 index 793c1db2e1..0000000000 --- a/skills/nextjs-15/SKILL.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -name: nextjs-15 -description: > - Next.js 15 App Router patterns. - Trigger: When working in Next.js App Router (app/), Server Components vs Client Components, Server Actions, Route Handlers, caching/revalidation, and streaming/Suspense. -license: Apache-2.0 -metadata: - author: prowler-cloud - version: "1.0" - scope: [root, ui] - auto_invoke: "App Router / Server Actions" -allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task ---- - -## App Router File Conventions - -``` -app/ -├── layout.tsx # Root layout (required) -├── page.tsx # Home page (/) -├── loading.tsx # Loading UI (Suspense) -├── error.tsx # Error boundary -├── not-found.tsx # 404 page -├── (auth)/ # Route group (no URL impact) -│ ├── login/page.tsx # /login -│ └── signup/page.tsx # /signup -├── api/ -│ └── route.ts # API handler -└── _components/ # Private folder (not routed) -``` - -## Server Components (Default) - -```typescript -// No directive needed - async by default -export default async function Page() { - const data = await db.query(); - return ; -} -``` - -## Server Actions - -```typescript -// app/actions.ts -"use server"; - -import { revalidatePath } from "next/cache"; -import { redirect } from "next/navigation"; - -export async function createUser(formData: FormData) { - const name = formData.get("name") as string; - - await db.users.create({ data: { name } }); - - revalidatePath("/users"); - redirect("/users"); -} - -// Usage -
- - -
-``` - -## Data Fetching - -```typescript -// Parallel -async function Page() { - const [users, posts] = await Promise.all([ - getUsers(), - getPosts(), - ]); - return ; -} - -// Streaming with Suspense -}> - - -``` - -## Route Handlers (API) - -```typescript -// app/api/users/route.ts -import { NextRequest, NextResponse } from "next/server"; - -export async function GET(request: NextRequest) { - const users = await db.users.findMany(); - return NextResponse.json(users); -} - -export async function POST(request: NextRequest) { - const body = await request.json(); - const user = await db.users.create({ data: body }); - return NextResponse.json(user, { status: 201 }); -} -``` - -## Middleware - -```typescript -// middleware.ts (root level) -import { NextResponse } from "next/server"; -import type { NextRequest } from "next/server"; - -export function middleware(request: NextRequest) { - const token = request.cookies.get("token"); - - if (!token && request.nextUrl.pathname.startsWith("/dashboard")) { - return NextResponse.redirect(new URL("/login", request.url)); - } - - return NextResponse.next(); -} - -export const config = { - matcher: ["/dashboard/:path*"], -}; -``` - -## Metadata - -```typescript -// Static -export const metadata = { - title: "My App", - description: "Description", -}; - -// Dynamic -export async function generateMetadata({ params }) { - const product = await getProduct(params.id); - return { title: product.name }; -} -``` - -## server-only Package - -```typescript -import "server-only"; - -// This will error if imported in client component -export async function getSecretData() { - return db.secrets.findMany(); -} -``` diff --git a/skills/nextjs-16/SKILL.md b/skills/nextjs-16/SKILL.md new file mode 100644 index 0000000000..272339c2da --- /dev/null +++ b/skills/nextjs-16/SKILL.md @@ -0,0 +1,160 @@ +--- +name: nextjs-16 +description: > + Next.js 16 App Router patterns. + Trigger: When working in Next.js App Router (app/), Server Components vs Client Components, Server Actions, Route Handlers, proxy.ts, caching/revalidation, Cache Components, and streaming/Suspense. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" + scope: [root, ui] + auto_invoke: "App Router / Server Actions" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## App Router File Conventions + +``` +app/ +├── layout.tsx # Root layout (required) +├── page.tsx # Home page (/) +├── loading.tsx # Loading UI (Suspense) +├── error.tsx # Error boundary +├── not-found.tsx # 404 page +├── (auth)/ # Route group (no URL impact) +│ ├── login/page.tsx # /login +│ └── signup/page.tsx # /signup +├── api/ +│ └── route.ts # API handler +└── _components/ # Private folder (not routed) +``` + +## Next.js 16 Notes + +- Use `proxy.ts` for request-boundary logic. `middleware.ts` is deprecated in Next.js 16. +- `proxy.ts` runs on the Node.js runtime and cannot be configured for Edge. +- Keep `proxy.ts` matchers narrow. Exclude `api`, static files, and image assets unless the route explicitly needs proxy logic. +- Route Handlers in `app/api/**/route.ts` are the right fit for health checks, webhooks, backend-for-frontend endpoints, and server-only proxy calls. + +## Server Components (Default) + +```typescript +// No directive needed - async by default +export default async function Page() { + const data = await db.query(); + return ; +} +``` + +## Server Actions + +```typescript +"use server"; + +import { revalidatePath } from "next/cache"; +import { redirect } from "next/navigation"; + +export async function createUser(formData: FormData) { + const name = formData.get("name") as string; + + await db.users.create({ data: { name } }); + + revalidatePath("/users"); + redirect("/users"); +} +``` + +## Data Fetching + +```typescript +async function Page() { + const [users, posts] = await Promise.all([getUsers(), getPosts()]); + + return ; +} + +}> + +; +``` + +## Caching and Revalidation + +```typescript +import { revalidatePath, revalidateTag } from "next/cache"; + +export async function refreshDashboard() { + "use server"; + + revalidatePath("/"); + revalidateTag("dashboard"); +} +``` + +- Use `revalidatePath` for route-level invalidation after mutations. +- Use `revalidateTag` when data fetches share a cache tag across routes. +- With Cache Components enabled, put `"use cache"` only in pure server-side cached functions. Do not cache auth, tenant-scoped, or per-user responses unless the cache key explicitly isolates them. + +## Route Handlers (API) + +```typescript +// app/api/users/route.ts +import { NextResponse } from "next/server"; + +export async function GET() { + const users = await db.users.findMany(); + return NextResponse.json(users); +} + +export async function POST(request: Request) { + const body = await request.json(); + const user = await db.users.create({ data: body }); + return NextResponse.json(user, { status: 201 }); +} +``` + +## Proxy + +```typescript +// proxy.ts (root level) +import { NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; + +export function proxy(request: NextRequest) { + const token = request.cookies.get("token"); + + if (!token && request.nextUrl.pathname.startsWith("/dashboard")) { + return NextResponse.redirect(new URL("/login", request.url)); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/dashboard/:path*"], +}; +``` + +## Metadata + +```typescript +export const metadata = { + title: "My App", + description: "Description", +}; + +export async function generateMetadata() { + const product = await getProduct(); + return { title: product.name }; +} +``` + +## server-only Package + +```typescript +import "server-only"; + +export async function getSecretData() { + return db.secrets.findMany(); +} +``` diff --git a/skills/prowler-ui/SKILL.md b/skills/prowler-ui/SKILL.md index 3e6407889e..bde8c966db 100644 --- a/skills/prowler-ui/SKILL.md +++ b/skills/prowler-ui/SKILL.md @@ -1,7 +1,7 @@ --- name: prowler-ui description: > - Prowler UI-specific patterns. For generic patterns, see: typescript, react-19, nextjs-15, tailwind-4. + Prowler UI-specific patterns. For generic patterns, see: typescript, react-19, nextjs-16, tailwind-4. Trigger: When working inside ui/ on Prowler-specific conventions (shadcn vs HeroUI legacy, folder placement, actions/adapters, shared types/hooks/lib). license: Apache-2.0 metadata: @@ -18,7 +18,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task - `typescript` - Const types, flat interfaces - `react-19` - No useMemo/useCallback, compiler -- `nextjs-15` - App Router, Server Actions +- `nextjs-16` - App Router, Server Actions - `tailwind-4` - cn() utility, styling rules - `zod-4` - Schema validation - `zustand-5` - State management @@ -28,7 +28,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task ## Tech Stack (Versions) ``` -Next.js 15.5.9 | React 19.2.2 | Tailwind 4.1.13 | shadcn/ui +Next.js 16.2.3 | React 19.2.5 | Tailwind 4.1.18 | shadcn/ui Zod 4.1.11 | React Hook Form 7.62.0 | Zustand 5.0.8 NextAuth 5.0.0-beta.30 | Recharts 2.15.4 HeroUI 2.8.4 (LEGACY - do not add new components) diff --git a/skills/prowler/SKILL.md b/skills/prowler/SKILL.md index 667ad0cc4b..35fae8b68a 100644 --- a/skills/prowler/SKILL.md +++ b/skills/prowler/SKILL.md @@ -18,7 +18,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task |-----------|-------|----------| | SDK | Python 3.10+, Poetry | `prowler/` | | API | Django 5.1, DRF, Celery | `api/` | -| UI | Next.js 15, React 19, Tailwind 4 | `ui/` | +| UI | Next.js 16, React 19, Tailwind 4 | `ui/` | | MCP | FastMCP 2.13.1 | `mcp_server/` | ## Quick Commands diff --git a/skills/react-19/SKILL.md b/skills/react-19/SKILL.md index 519ae9f15e..645292aa83 100644 --- a/skills/react-19/SKILL.md +++ b/skills/react-19/SKILL.md @@ -2,7 +2,7 @@ name: react-19 description: > React 19 patterns with React Compiler. - Trigger: When writing React 19 components/hooks in .tsx (React Compiler rules, hook patterns, refs as props). If using Next.js App Router/Server Actions, also use nextjs-15. + Trigger: When writing React 19 components/hooks in .tsx (React Compiler rules, hook patterns, refs as props). If using Next.js App Router/Server Actions, also use nextjs-16. license: Apache-2.0 metadata: author: prowler-cloud diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 40cf77dc1a..b0d131f10e 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -5,7 +5,7 @@ > - [`prowler-test-ui`](../skills/prowler-test-ui/SKILL.md) - Playwright E2E testing (comprehensive) > - [`typescript`](../skills/typescript/SKILL.md) - Const types, flat interfaces > - [`react-19`](../skills/react-19/SKILL.md) - No useMemo/useCallback, compiler -> - [`nextjs-15`](../skills/nextjs-15/SKILL.md) - App Router, Server Actions +> - [`nextjs-16`](../skills/nextjs-16/SKILL.md) - App Router, Server Actions > - [`tailwind-4`](../skills/tailwind-4/SKILL.md) - cn() utility, no var() in className > - [`zod-4`](../skills/zod-4/SKILL.md) - New API (z.email(), z.uuid()) > - [`zustand-5`](../skills/zustand-5/SKILL.md) - Selectors, persist middleware @@ -21,7 +21,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Action | Skill | |--------|-------| | Add changelog entry for a PR or feature | `prowler-changelog` | -| App Router / Server Actions | `nextjs-15` | +| App Router / Server Actions | `nextjs-16` | | Building AI chat features | `ai-sdk-5` | | Committing changes | `prowler-commit` | | Create PR that requires changelog entry | `prowler-changelog` | @@ -179,7 +179,7 @@ test("action works", { tag: ["@critical", "@feature"] }, async ({ page }) => { ## TECH STACK -Next.js 15.5.9 | React 19.2.2 | Tailwind 4.1.13 | shadcn/ui +Next.js 16.2.3 | React 19.2.5 | Tailwind 4.1.18 | shadcn/ui Zod 4.1.11 | React Hook Form 7.62.0 | Zustand 5.0.8 | NextAuth 5.0.0-beta.30 | Recharts 2.15.4 > **Note**: HeroUI exists in `components/ui/` as legacy code. Do NOT add new components there.