React 19 + Next.js 16 + Ant Design — Clean Architecture
Skill for creating and maintaining React 19 + Next.js 16 frontends with feature architecture, Ant Design, and REST integration (.NET or similar).
When to use
- Create or extend Next.js frontend (admin, SaaS, backoffice)
- CRUD, forms, authenticated layout
- Integrate with REST API
- Refactor React components to vertical slice
- Define service, hook, schema, and route patterns
Expected structure
src/app/ → routes, layouts, loading, error, not-found (NO business logic)
src/features/ → domains (auth, products, …)
src/shared/ → components, providers, lib (api, auth, env), theme/
UI URLs vs API
| Layer |
Convention |
Example |
| UI routes |
English |
/products, /products/new, /products/:id/edit |
| REST API |
English |
/api/products |
Architecture rules
src/app — Next.js only (thin routes importing pages from features/)
src/features/{domain}/ — types, schemas, services, hooks, components, {domain}.page.tsx
src/shared/ — reusable, no domain logic
- HTTP centralized in
shared/lib/api/api-client.ts
process.env only in shared/lib/env/env.ts
- Forms: React Hook Form + Zod
- Remote state: TanStack Query
- UI: Ant Design (no Tailwind in MVP)
- Design system in
shared/theme/ — palette, CSS tokens, overrides in theme/styles/antd/
- Drawer/menu:
rootClassName="app-drawer" + CSS .app-drawer .drawer-menu (portaled to body)
- SEO:
shared/lib/seo/metadata.ts + metadata per route; noindex in admin app
- Forbidden:
any, Axios directly in visual components; legacy redirects without need
Ant Design + App Router
// src/app/layout.tsx
import { AntdRegistry } from '@ant-design/nextjs-registry';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en-US">
<body>
<AntdRegistry>{children}</AntdRegistry>
</body>
</html>
);
}
Separate provider with ConfigProvider, en_US locale, centralized theme.
Server vs Client Components
'use client' |
Server Component |
| Interactive Ant Design |
Route that only re-exports feature page |
| useRouter, useState, useEffect |
redirect(), metadata |
| TanStack Query, React Hook Form |
Layout without interactivity |
| localStorage, events |
— |
Service pattern
import { apiClient } from '@/shared/lib/api/api-client';
export async function listProducts(): Promise<Product[]> {
return apiClient.get<Product[]>('/api/products');
}
- Services are pure async functions
- Must not use hooks or JSX
Hook pattern
'use client';
import { useQuery } from '@tanstack/react-query';
export function useProducts() {
return useQuery({ queryKey: ['products'], queryFn: listProducts });
}
- Hooks must not return JSX
- Mutations invalidate related query keys
Form pattern
export const productSchema = z.object({
name: z.string().min(1, 'Name is required.'),
price: z.number().positive('Price must be greater than zero.'),
});
Component: useForm + zodResolver + Controller + Ant Design Form.Item.
Test conventions
- Test Zod schemas with
safeParse (Vitest)
- File:
{feature}.schema.test.ts next to the schema
- Do not test Ant Design internal implementation
- Prefer contract tests (schema, mocked service) over UI snapshots
New feature — checklist
- types → 2. schema (+ test) → 3. service → 4. hooks → 5. components → 6. page → 7. route in app/
Reference
Detailed examples in reference.md.
1---2name: react-nextjs-antd-clean-architecture-23description: React 19 + Next.js 16 App Router, TypeScript, Ant Design, TanStack Query, Axios, React Hook Form, Zod — Clean Architecture frontend with vertical slice by feature. Use when creating or refactoring Next.js apps, admin panels, SaaS frontends, CRUDs, forms, layouts and frontend architecture.4---56# React 19 + Next.js 16 + Ant Design — Clean Architecture78Skill for creating and maintaining React 19 + Next.js 16 frontends with feature architecture, Ant Design, and REST integration (.NET or similar).910## When to use1112- Create or extend Next.js frontend (admin, SaaS, backoffice)13- CRUD, forms, authenticated layout14- Integrate with REST API15- Refactor React components to vertical slice16- Define service, hook, schema, and route patterns1718## Expected structure1920```txt21src/app/ → routes, layouts, loading, error, not-found (NO business logic)22src/features/ → domains (auth, products, …)23src/shared/ → components, providers, lib (api, auth, env), theme/24```2526## UI URLs vs API2728| Layer | Convention | Example |29|---|---|---|30| UI routes | English | `/products`, `/products/new`, `/products/:id/edit` |31| REST API | English | `/api/products` |3233## Architecture rules34351. `src/app` — Next.js only (thin routes importing pages from `features/`)362. `src/features/{domain}/` — types, schemas, services, hooks, components, `{domain}.page.tsx`373. `src/shared/` — reusable, **no** domain logic384. HTTP centralized in `shared/lib/api/api-client.ts`395. `process.env` only in `shared/lib/env/env.ts`406. Forms: **React Hook Form + Zod**417. Remote state: **TanStack Query**428. UI: **Ant Design** (no Tailwind in MVP)439. Design system in `shared/theme/` — palette, CSS tokens, overrides in `theme/styles/antd/`4410. Drawer/menu: `rootClassName="app-drawer"` + CSS `.app-drawer .drawer-menu` (portaled to body)4511. SEO: `shared/lib/seo/metadata.ts` + metadata per route; `noindex` in admin app4612. Forbidden: `any`, Axios directly in visual components; legacy redirects without need4748## Ant Design + App Router4950```tsx51// src/app/layout.tsx52import { AntdRegistry } from '@ant-design/nextjs-registry';5354export default function RootLayout({ children }: { children: React.ReactNode }) {55 return (56 <html lang="en-US">57 <body>58 <AntdRegistry>{children}</AntdRegistry>59 </body>60 </html>61 );62}63```6465Separate provider with `ConfigProvider`, `en_US` locale, centralized theme.6667## Server vs Client Components6869| `'use client'` | Server Component |70|---|---|71| Interactive Ant Design | Route that only re-exports feature page |72| useRouter, useState, useEffect | redirect(), metadata |73| TanStack Query, React Hook Form | Layout without interactivity |74| localStorage, events | — |7576## Service pattern7778```ts79import { apiClient } from '@/shared/lib/api/api-client';8081export async function listProducts(): Promise<Product[]> {82 return apiClient.get<Product[]>('/api/products');83}84```8586- Services are pure async functions87- **Must not** use hooks or JSX8889## Hook pattern9091```ts92'use client';9394import { useQuery } from '@tanstack/react-query';9596export function useProducts() {97 return useQuery({ queryKey: ['products'], queryFn: listProducts });98}99```100101- Hooks **must not** return JSX102- Mutations invalidate related query keys103104## Form pattern105106```ts107export const productSchema = z.object({108 name: z.string().min(1, 'Name is required.'),109 price: z.number().positive('Price must be greater than zero.'),110});111```112113Component: `useForm` + `zodResolver` + `Controller` + Ant Design `Form.Item`.114115## Test conventions116117- Test Zod schemas with `safeParse` (Vitest)118- File: `{feature}.schema.test.ts` next to the schema119- Do not test Ant Design internal implementation120- Prefer contract tests (schema, mocked service) over UI snapshots121122## New feature — checklist1231241. types → 2. schema (+ test) → 3. service → 4. hooks → 5. components → 6. page → 7. route in app/125126## Reference127128Detailed examples in [`reference.md`](reference.md).