# ارتقای Next.js از 15 به 16 (آخرین نسخه) + فعال‌سازی امکانات جدید

## پروژه

`nobat724_front`

## زمینه

پروژه روی `next@15.5.7` و `react@18.3.1` است (React با `overrides` در `package.json` روی 18 پین شده). آخرین نسخه پایدار Next.js نسخه **16.3.x** است (16.2.10 LTS هم موجود است — هدف این ارتقا `next@latest` یعنی 16.3.x). Next 16 چند breaking change دارد (React 19 اجباری، حذف `next lint`، deprecate شدن `middleware` به نفع `proxy`، Turbopack به‌عنوان پیش‌فرض build/dev) و چند قابلیت جدید (Cache Components، React Compiler، Instant Navigations / Partial Prefetching در 16.3).

**تمام کار باید روی برنچ جدا انجام شود** — `main` دست نخورد.

## مشکل / هدف

1. ارتقای `next` به آخرین نسخه (16.3.x) و `react`/`react-dom` به 19
2. رفع همه breaking changeها تا `npm run build` و `npm run test` سبز شود
3. فعال‌سازی امکانات جدید نسخه 16 که با معماری multi-domain پروژه سازگارند
4. رفتار SEO فعلی (متادیتا داخل `<head>`، canonical، sitemap، robots) عیناً حفظ شود

## فایل‌های مرتبط

| فایل | نقش |
|------|-----|
| `package.json` | نسخه‌ها، `overrides` پین React 18، اسکریپت `next lint` |
| `next.config.js` | کانفیگ — شامل `htmlLimitedBots: /.*/` (فیکس SEO، **نباید حذف شود**)، `output: 'standalone'`، CSP headers |
| `middleware.js` | تزریق هدر `x-pathname` برای canonical — در 16 باید به `proxy.js` تبدیل شود |
| `app/layout.js` | `generateMetadata` مبتنی بر host (multi-domain) |
| `lib/getStateInfo.js`, `lib/getCanonicalUrl.js`, `lib/auth.js` | خواندن `headers()`/`cookies()` — ۱۰ فایل از `next/headers` استفاده می‌کنند |
| `app/doctor/[slug]/page.js`, `app/clinic/[slug]/page.js`, `app/blog/[slug]/page.js`, `app/sitemap.js` | fetch با `next: { revalidate: 3600, tags: [...] }` |
| `Dockerfile`, `nixpacks.toml`, `liara.json` | deploy — خروجی standalone |
| `vitest.config.mjs`, `test/` | تست‌ها با vitest + @testing-library/react |

## وضعیت فعلی

```json
// package.json (بخش‌های مرتبط)
"scripts": {
  "dev": "cross-env HOST=yazd-nobat.localhost PORT=3000 NODE_TLS_REJECT_UNAUTHORIZED=0 next dev",
  "build": "next build",
  "lint": "next lint"
},
"dependencies": {
  "next": "^15.5.7",
  "@next/third-parties": "^15.5.7",
  "react": "^18.3.1",
  "react-dom": "^18.3.1",
  "@mui/material": "^5.18.0",
  "@mui/x-charts": "^7.29.1",
  "@mui/x-date-pickers": "^7.29.4"
},
"overrides": {
  "react": "^18.3.1",
  "react-dom": "^18.3.1"
}
```

```js
// middleware.js — کل فایل
import { NextResponse } from 'next/server';

export function middleware(request) {
    const response = NextResponse.next();
    response.headers.set('x-pathname', request.nextUrl.pathname);
    return response;
}

export const config = {
    matcher: [
        '/((?!api|_next/static|_next/image|favicon.ico|panel|dashboard|login|login-verify).*)',
    ],
};
```

نکات پیش‌بررسی‌شده (لازم نیست دوباره جستجو شوند):

- هیچ استفاده‌ای از `legacyBehavior`، `useFormState`، `publicRuntimeConfig`/`serverRuntimeConfig`، `getInitialProps`، `next/legacy/image`، prop سفارشی `quality` روی `<Image>`، custom webpack config، یا `export const dynamic/revalidate` در پروژه **وجود ندارد**.
- `await params` از قبل در همه صفحات dynamic رعایت شده (الگوی Next 15).
- هیچ فایل کانفیگ ESLint وجود ندارد (`next lint` بدون config اجرا می‌شده) و `eslint` در devDependencies نیست.
- Node محلی v22 است (Next 16 حداقل 20.9 می‌خواهد — OK).

## وظایف

### ۱. ساخت برنچ

```bash
cd nobat724_front
git checkout -b upgrade/next-16
```

همه commitها روی این برنچ. به `main` هیچ چیزی push نشود.

### ۲. ارتقای پکیج‌ها

```bash
npx @next/codemod@latest upgrade latest
```

اگر codemod به هر دلیل کامل اجرا نشد، دستی:

```bash
npm install next@latest react@latest react-dom@latest @next/third-parties@latest
```

- بخش `overrides` (پین React 18) از `package.json` **حذف شود** — دلیل پین، سازگاری قدیمی MUI بود؛ `@mui/material@5.18` و `@mui/x-*@7.29` هر دو peer-dep React 19 را پشتیبانی می‌کنند.
- اگر پکیج‌های قدیمی (`react-google-map-picker`، `react-images-uploading`، `aos`) خطای peer-dep برای React 19 دادند: اول `npm install --legacy-peer-deps` را امتحان کن و در گزارش نهایی صریح ذکر کن؛ سپس در مرحله تست، صفحات استفاده‌کننده از این پکیج‌ها را در مرورگر چک کن (map picker در پنل، آپلود عکس، انیمیشن‌های AOS صفحه اصلی).
- `@testing-library/react@16` و `vitest@2` با React 19 سازگارند؛ اگر تست‌ها خطای rendering دادند فقط نسخه `@testing-library/react` را به آخرین minor ارتقا بده.

### ۳. تبدیل `middleware.js` به `proxy.js`

در Next 16 نام `middleware` deprecated و جایگزینش `proxy` است. فایل `middleware.js` را به `proxy.js` تغییر نام بده و تابع را rename کن:

```js
// proxy.js
import { NextResponse } from 'next/server';

export function proxy(request) {
    const response = NextResponse.next();
    response.headers.set('x-pathname', request.nextUrl.pathname);
    return response;
}

export const config = {
    matcher: [
        '/((?!api|_next/static|_next/image|favicon.ico|panel|dashboard|login|login-verify).*)',
    ],
};
```

**تست حیاتی بعد از این تغییر:** هدر `x-pathname` باید همچنان برسد — `curl -s http://yazd-nobat.localhost:3000/doctors | grep canonical` باید `https://nobat724.com/doctors` بدهد (اگر header نرسد، `getCanonicalUrl` مقدار `null` برمی‌گرداند و تگ canonical حذف می‌شود — این یعنی regression).

### ۴. جایگزینی `next lint`

`next lint` در Next 16 حذف شده. چون هیچ کانفیگ ESLint موجود نیست:

```bash
npm install -D eslint eslint-config-next
```

فایل `eslint.config.mjs` (flat config) بساز:

```js
import { FlatCompat } from '@eslint/eslintrc';

const compat = new FlatCompat({ baseDirectory: import.meta.dirname });

export default [
  ...compat.extends('next/core-web-vitals'),
];
```

و در `package.json`:

```json
"lint": "eslint app components lib services hooks context utils helper"
```

خطاهای lint موجود را فیکس نکن (خارج از scope) — فقط مطمئن شو دستور اجرا می‌شود؛ در صورت نیاز سطح خطاهای پرتکرار را در config به `warn` تنزل بده.

### ۵. Turbopack (پیش‌فرض جدید dev و build)

Next 16 هم `next dev` و هم `next build` را با Turbopack اجرا می‌کند. پروژه custom webpack config ندارد، پس انتظار سازگاری می‌رود. فقط verify کن:

- `npm run dev` بالا بیاید و صفحه اول، `/doctors`، `/doctor/[slug]` (یک uuid واقعی از خروجی `/doctors`) و `/panel` بدون خطای کنسول رندر شوند
- `npm run build` موفق شود و خروجی `standalone` تولید کند (برای Docker/liara لازم است — `ls .next/standalone`)
- استایل‌های emotion RTL (`stylis-plugin-rtl` در `mui/index.js` یا `ThemeRegistry`) درست کار کنند — یک صفحه را چک کن که دکمه‌ها/فرم‌ها RTL باشند

اگر Turbopack با emotion/styled-components مشکل داشت، ابتدا `compiler.styledComponents: true` را در `next.config.js` امتحان کن؛ فقط به‌عنوان آخرین راه‌حل build را با فلگ `--webpack` برگردان و دلیل را در گزارش بنویس.

### ۶. فعال‌سازی React Compiler

قابلیت پایدار نسخه 16 (و در 16.3 پشتیبانی Rust در Turbopack):

```bash
npm install -D babel-plugin-react-compiler
```

```js
// next.config.js
const nextConfig = {
  reactCompiler: true,
  // ...
};
```

بعد از فعال‌سازی، `npm run build` و تست‌های vitest باید سبز بمانند. اگر کامپایلر روی کامپوننت خاصی خطا داد (کامپوننت‌های کلاسی یا الگوهای غیراستاندارد)، همان کامپوننت را با `"use no memo"` مستثنا کن — کل قابلیت را خاموش نکن.

### ۷. Cache Components — ارزیابی محتاطانه (فعال‌سازی مشروط)

`cacheComponents: true` مدل کش جدید نسخه 16 است (`"use cache"`, `cacheLife`, `cacheTag`) و پیش‌نیاز Partial Prefetching در 16.3.

**هشدار معماری:** این پروژه multi-domain است — `generateMetadata` و layout و ده فایل دیگر به `headers()` (هدر `host`) وابسته‌اند؛ خروجی هر صفحه per-host متفاوت است. با `cacheComponents`، هر چیزی که `headers()` می‌خواند dynamic می‌ماند و کش کردنش باعث نشت محتوای یک شهر به دامنه شهر دیگر می‌شود.

ترتیب کار:

1. ابتدا **بدون** فعال‌سازی، fetchهای موجود را دست‌نخورده بگذار — الگوی `next: { revalidate: 3600, tags: [...] }` در Next 16 همچنان پشتیبانی می‌شود
2. `cacheComponents: true` را روی یک commit جدا فعال کن و `npm run build` بگیر
3. اگر build خطای «uncached data access» برای مسیرهای متکی به `headers()` داد و رفعش نیاز به `Suspense`گذاری گسترده یا `"use cache"` روی توابع host-dependent داشت → **فعال‌سازی را revert کن** و در گزارش نهایی بنویس چرا (این قابلیت برای این معماری فعلاً امن نیست)
4. اگر build پاس شد → با دو host تست کن (`HOST=yazd-nobat.localhost` و یک شهر دیگر از `data/city.json` مثلاً با تغییر موقت HOST در اسکریپت dev) و مطمئن شو title/description/canonical هر دامنه مستقل است

### ۸. تمیزکاری‌های کانفیگ نسخه 16

در `next.config.js`:

- `htmlLimitedBots: /.*/` **باید بماند** — فیکس عمدی برای رندر متادیتا داخل `<head>` است (streaming metadata خاموش). بعد از ارتقا با `curl -s -A "Mozilla/5.0" http://yazd-nobat.localhost:3000/ | python3 -c "import sys; h=sys.stdin.read(); e=h.find('</head>'); print('HEAD' if 0<=h.find('rel=\"canonical\"')<e else 'BODY')"` تأیید کن هنوز `HEAD` است
- `images.minimumCacheTTL` در 16 پیش‌فرض ۴ ساعت شده — نیازی به تغییر نیست، فقط بدان
- `env.DEV_MODE` و CSP headers و `output: 'standalone'` دست نخورند

### ۹. تست نهایی و commit

```bash
npm run test          # همه تست‌های vitest سبز
npm run build         # build موفق با Turbopack
npm run lint          # اجرای eslint بدون crash
```

بعد smoke test دستی با dev server:

- `/` — صفحه اصلی، جستجو، تصاویر next/image
- `/doctors` و `/doctor/[uuid]` — لیست و صفحه پزشک + JSON-LD
- `/blogs` و `/blog/[slug]`
- `/login` — فلوی OTP (فقط رندر فرم؛ ارسال واقعی لازم نیست)
- view-source صفحه اول: متادیتا (`keywords`, `canonical`, `og:*`, `twitter:*`) داخل `<head>`

Commitها را مرحله‌ای بزن (ارتقا پکیج‌ها / proxy / eslint / react compiler / cache components هرکدام جدا) تا در صورت مشکل، revert تکی ممکن باشد.

## نکات مهم

- **برنچ:** همه‌چیز روی `upgrade/next-16`؛ merge به `main` با کاربر است، خودت merge نکن.
- **SEO regression خط قرمز است:** canonical به `https://nobat724.com/<path>`، متادیتا در `<head>`، `robots.js` و `sitemap.js` باید عیناً مثل قبل کار کنند.
- ده فایل از `next/headers` استفاده می‌کنند — همه `await headers()` هستند (الگوی 15)؛ در 16 هم همین درست است.
- `services/response.js` قرارداد API با backend (`clinicpro`) است — این ارتقا نباید هیچ تغییری در آن بدهد.
- اسکریپت dev به `NODE_TLS_REJECT_UNAUTHORIZED=0` و `HOST` سفارشی وابسته است — بدون تغییر بماند.
- اگر در حین کار مستندات لازم شد: راهنمای رسمی مهاجرت `https://nextjs.org/docs/app/guides/upgrading/version-16` و بلاگ‌های `nextjs.org/blog/next-16`, `next-16-1`, `next-16-2`, و 16.3.
- بعد از اتمام: `graphify update .` در روت workspace اجرا شود.
