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.